Take a look:
Double-checked locking example
public static Singleton
getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
//1
if (instance == null)
//2 instance = new Singleton();
//3
}
}
return instance;
}
The theory behind double-checked locking is that the second check at //2 makes it impossible for two different Singleton
objects to be created. Consider the following sequence of events:- Thread 1 enters the
getInstance()
method. - Thread 1 enters the
synchronized
block at //1 becauseinstance
isnull
. - Thread 1 is preempted by thread 2.
- Thread 2 enters the
getInstance()
method. - Thread 2 attempts to acquire the lock at //1 because
instance
is stillnull
. However, because thread 1 holds the lock, thread 2 blocks at //1. - Thread 2 is preempted by thread 1.
- Thread 1 executes and because instance is still
null
at //2, creates aSingleton
object and assigns its reference toinstance
. - Thread 1 exits the
synchronized
block and returns instance from thegetInstance()
method. - Thread 1 is preempted by thread 2.
- Thread 2 acquires the lock at //1 and checks to see if
instance
isnull
. - Because
instance
is non-null
, a secondSingleton
object is not created and the one created by thread 1 is returned.
The theory behind double-checked locking is perfect. Unfortunately, reality is entirely different. The problem with double-checked locking is that there is no guarantee it will work on single or multi-processor machines.
The issue of the failure of double-checked locking is not due to implementation bugs in JVMs but to the current Java platform memory model. The memory model allows what is known as "out-of-order writes" and is a prime reason why this idiom fails. The problem with this code is that the variable instance can become non-null before the body of the Singleton constructor executes.
Source: http://www.ibm.com/developerworks/java/library/j-dcl/index.htmlInstead of DCL you can use:
1. You don't need lazy initializing
public class Singleton1 {
private static final Singleton1 instance = new Singleton1();
public static Singleton1 getInstance() {
return instance;
}
}
2. You need lazy initializing and you can ignore synchronization expenses
public class Singleton2 {
private static final Singleton2 instance;
public synchronized static Singleton2 getInstance() {
if (instance == null)
instance = new Singleton2();
return instance;
}
}
In modern JVM these expenses are minimal.3. You need lazy initializing and you can't ignore synchronization expenses
public class Singleton3 {
private static class Instance {
static final Singleton3 value = new Singleton3();
}
public static Singleton3 getInstance() {
return Instance.value;
}
}
In that case static inner class will be loaded when getInstance() method will be called.