I've seen the double-checked singleton pattern before, and at first thought it would work. It's an attempt to reduce the penalty of requiring synchronized access to obtain a singleton.
Essentially the pattern is as follows:
public class Singleton { private static Singleton instance; public static Singleton getInstance() { if (instance == null) { synchronized(Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
This doesn't work. Unfortunately the reason why it doesn't work isn't immediately obvious. It looks like it should. There's a good description of why it doesn't work on IBM's developerWorks.
This doesn't work due to the way most JITs process code, and may not work simply do to the way some processors cache data. In short, it won't work.
So the next bright idea would be simply to add volatile
to the singleton. Unfortunately, that also doesn't work prior to Java 5. The developerWorks article explains why, but essentially, volatile
doesn't work. Bill Pugh also explains why in The "Double-Checked Locking is Broken" Declaration.
Ultimately, using volatile
offers no performance improvement in Java 5 over the simplest method of making it thread safe:
public class Singleton { private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
Another clever solution that Bill Pugh suggests is something like the following:
public class Singleton { private static class SingletonHolder { private static Singleton instance = new Singleton; } public static Singleton getInstance() { return SingletonHolder.instance; } }
This relies on the class-loading mechanics to deal with locking for us. I'm unclear if it offers any improvement over simply synchronizing the getInstance()
method in the first place, though.