Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 5 of 6
Since double-checked locking is not guaranteed to work, you must synchronize the entire getInstance() method. However, another alternative is simple, fast, and thread-safe.
Example 7 lists a simple, fast, and thread-safe singleton implementation:
public class Singleton {
public final static Singleton INSTANCE = new Singleton();
private Singleton() {
// Exists only to defeat instantiation.
}
}
The preceding singleton implementation is thread-safe because static member variables created when declared are guaranteed to be created the first time they are accessed. You get a thread-safe implementation that automatically employs lazy instantiation; here's how you use it:
Singleton singleton = Singleton.INSTANCE;
singleton.dothis();
singleton.dothat();
...
Of course, like nearly everything else, the preceding singleton is a compromise; if you use that implementation, you can't
change your mind and allow multiple singleton instances later on. With a more conservative singleton implementation, instances
are obtained through a getInstance() method, and you can change those methods to return a unique instance or one of hundreds. You can't do the same with a public
static member variable.
You can safely use Example 7's singleton implementation or Example 1's implementation with a synchronized getInstance() method. However, we must explore another issue: You must specify the singleton class at compile time, which is not very flexible.
A registry of singletons will let us specify singleton classes at runtime.
Use a singleton registry to:
Example 8 lists a singleton class that maintains a registry of singletons, registered by class name:
import java.util.HashMap;
import org.apache.log4j.Logger;
public class Singleton {
private static HashMap map = new HashMap();
private static Logger logger = Logger.getRootLogger();
protected Singleton() {
// Exists only to thwart instantiation
}
public static synchronized Singleton getInstance(String classname) {
if(classname == null) throw new IllegalArgumentException("Illegal classname");
Singleton singleton = (Singleton)map.get(classname);
if(singleton != null) {
logger.info("got singleton from map: " + singleton);
return singleton;
}
if(classname.equals("SingeltonSubclass_One"))
singleton = new SingletonSubclass_One();
else if(classname.equals("SingeltonSubclass_Two"))
singleton = new SingletonSubclass_Two();
map.put(classname, singleton);
logger.info("created singleton: " + singleton);
return singleton;
}
// Assume functionality follows that's attractive to inherit
}
The preceding base class creates subclass instances and stores them in a map. But that base class is high maintenance because
you must update its getInstance() method for every subclass. Luckily, we can use reflection to skirt that issue.