Top 10 in 2008
5 popular archives:
All selections are based on page views.
JW hot topic: Tech careers in a slump
Seems like new layoffs are announced every week, projects are dying and software developers are feeling the IT budget squeeze.
Being nervous isn't a crime, but you're better off with information, advice, and a plan.
From the IDG News Network:
Page 3 of 7
Example 1's ClassicSingleton.getInstance() method is not thread-safe because of the following code:
1: if(instance == null) {
2: instance = new Singleton();
3: }
If a thread is preempted at Line 2 before the assignment is made, the instance member variable will still be null, and another thread can subsequently enter the if block. In that case, two distinct singleton instances will be created. Unfortunately, that scenario rarely occurs and is
therefore difficult to produce during testing. To illustrate this thread Russian roulette, I've forced the issue by reimplementing
Example 1's class. Example 4 shows the revised singleton class:
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");
}
}
}
Example 4's singleton resembles Example 1's class, except the singleton in the preceding listing stacks the deck to force
a multithreading error. The first time the getInstance() method is called, the thread that invoked the method sleeps for 50 milliseconds, which gives another thread time to call
getInstance() and create a new singleton instance. When the sleeping thread awakes, it also creates a new singleton instance, and we have
two singleton instances. Although Example 4's class is contrived, it stimulates the real-world situation where the first thread
that calls getInstance() gets preempted.
Example 5 tests Example 4's singleton:
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);
}
}
}
Example 5's test case creates two threads, starts each one, and waits for them to finish. The test case maintains a static
reference to a singleton instance, and each thread calls Singleton.getInstance(). If the static member variable has not been set, the first thread sets it to the singleton obtained with the call to getInstance(), and the static member variable is compared to the local variable for equality.
bug?By Anonymous on October 15, 2008, 5:07 amwhy is the method getInstance not synchronized? It could cause some race conditions.
Reply | Read entire comment
View all comments