1: if(instance == null) { 2: instance = new Singleton(); 3: }
import org.apache.log4j.Logger; public class Singleton { private static Singleton singleton = null; private static Logger logger = Logger.getRootLogger(); private static boolean firstThread = true; protected Singleton() { // Exists only to defeat instantiation. } public static Singleton getInstance() { if(singleton == null) { simulateRandomActivity(); singleton = new Singleton(); } logger.info("created singleton: " + singleton); return singleton; } private static void simulateRandomActivity() { try { if(firstThread) { firstThread = false; logger.info("sleeping..."); // This nap should give the second thread enough time // to get by the first thread. Thread.currentThread().sleep(50); } } catch(InterruptedException ex) { logger.warn("Sleep interrupted"); } } }
import org.apache.log4j.Logger; import junit.framework.Assert; import junit.framework.TestCase; public class SingletonTest extends TestCase { private static Logger logger = Logger.getRootLogger(); private static Singleton singleton = null; public SingletonTest(String name) { super(name); } public void setUp() { singleton = null; } public void testUnique() throws InterruptedException { // Both threads call Singleton.getInstance(). Thread threadOne = new Thread(new SingletonTestRunnable()), threadTwo = new Thread(new SingletonTestRunnable()); threadOne.start(); threadTwo.start(); threadOne.join(); threadTwo.join(); } private static class SingletonTestRunnable implements Runnable { public void run() { // Get a reference to the singleton. Singleton s = Singleton.getInstance(); // Protect singleton member variable from // multithreaded access. synchronized(SingletonTest.class) { if(singleton == null) // If local reference is null... singleton = s; // ...set it to the singleton } // Local reference must be equal to the one and // only instance of Singleton; otherwise, we have two // Singleton instances. Assert.assertEquals(true, s == singleton); } } }
Buildfile: build.xml init: [echo] Build 20030414 (14-04-2003 03:06) compile: run-test-text: INFO Thread-1: sleeping... INFO Thread-2: created singleton: Singleton@7e5cbd INFO Thread-1: created singleton: Singleton@704ebb junit.framework.AssertionFailedError: expected: but was: at junit.framework.Assert.fail(Assert.java:47) at junit.framework.Assert.failNotEquals(Assert.java:282) at junit.framework.Assert.assertEquals(Assert.java:64) at junit.framework.Assert.assertEquals(Assert.java:149) at junit.framework.Assert.assertEquals(Assert.java:155) at SingletonTest$SingletonTestRunnable.run(Unknown Source) at java.lang.Thread.run(Thread.java:554) [java] . [java] Time: 0.577 [java] OK (1 test)
public synchronized static Singleton getInstance() { if(singleton == null) { simulateRandomActivity(); singleton = new Singleton(); } logger.info("created singleton: " + singleton); return singleton; }
Buildfile: build.xml init: [echo] Build 20030414 (14-04-2003 03:15) compile: [javac] Compiling 2 source files run-test-text: INFO Thread-1: sleeping... INFO Thread-1: created singleton: Singleton@ef577d INFO Thread-2: created singleton: Singleton@ef577d [java] . [java] Time: 0.513 [java] OK (1 test)