The Double-Check Locking (DCL) idiom is an attempt to instantiate a singleton object in a lazy manner, where the singleton object is not created until the first time it is needed.
The problem with this approach is that it is flawed and does not work. For an in-depth understanding of why this idiom will not work, see:
While Brian Goetz goes into great detail about the reason for idiom failing, for the sake of brevity, the problem can be summed up in the following paragraph:
DCL relies on an unsynchronized use of the resource field. That appears to be harmless, but it is not. To see why, imagine that thread A is inside the synchronized block, executing the statement resource = new Resource(); while thread B is just entering getResource(). Consider the effect on memory of this initialization. Memory for the new Resource object will be allocated; the constructor for Resource will be called, initializing the member fields of the new object; and the field resource of SomeClass will be assigned a reference to the newly created object.
In short, the Java Memory Model (JMM) does not guarantee that given two threads, one will not see a partially constructed instance of the instance
field, since the instance
field is observed outside of a synchronized block (i.e., if (instance == null)
).
Note that as of JDK 5, the double-checked locking idiom is possible, but it is still delicate and should be avoided whenever another alternative can be used.
The reason developers attempted to create the DCL idiom in the first place is that use of the synchronized
keyword can result in a performance hit (according to Brian Goetz's article, as much as 100x).
The second pattern is a much simpler approach to the singleton pattern since it makes the singleton object static
, which ensures that for all outside objects that attempt to access the singleton, only one object will ever be created. This approach is called eager instantiation because the instance
object is created prior to any outside object needing it. Eager instantiation will usually suffice unless there is major overhead in creating the singleton object.
If lazy instantiation is required, a clever approach is to create a separate class with only the singleton instance as a static
field:
public class Singleton {
public static Singleton instance = new Singleton();
}
Since static
fields are not initialized in Java until the class is loaded by the classloader, the instance
object will not be instantiated until an outside object references the instance
object. Thus, we have achieved lazy instantiation through the compiler and Java runtime environment.