From Head First design patterns book, the singleton pattern with double checked locking has been implemented as below:
public class Singleton {
private volatile static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
I don't understand why volatile
is being used. Doesn't volatile
usage defeat the purpose of using double checked locking i.e performance?
If you didn't have it, a second thread could get into the synchronized block after the first set it to null, and your local cache would still think it was null.
The first one is not for correctness (if it were you are correct that it would be self defeating) but rather for optimization.
Well, there's no double-checked locking for performance. It is a broken pattern.
Leaving emotions aside,
volatile
is here because without it by the time second thread passesinstance == null
, first thread might not constructnew Singleton()
yet: no one promises that creation of the object happens-before assignment toinstance
for any thread but the one actually creating the object.volatile
in turn establishes happens-before relation between reads and writes, and fixes the broken pattern.If you are looking for performance, use holder inner static class instead.
A good resource for understanding why
volatile
is needed comes from the JCIP book. Wikipedia has a decent explanation of that material as well.The real problem is that
Thread A
may assign a memory space forinstance
before it is finished constructinginstance
.Thread B
will see that assignment and try to use it. This results inThread B
failing because it is using a partially constructed version ofinstance
.A volatile read is not really expensive in itself.
You can design a test to call
getInstance()
in a tight loop, to observe the impact of a volatile read; however that test is not realistic; in such situation, programmer usually would callgetInstance()
once and cache the instance for the duration of use.Another impl is by using a
final
field (see wikipedia). This requires an additional read, which may become more expensive than thevolatile
version. Thefinal
version may be faster in a tight loop, however that test is moot as previously argued.As quoted by @irreputable, volatile is not expensive. Even if it is expensive, consistency should be given priority over performance.
There is one more clean elegant way for Lazy Singletons.
Source article : Initialization-on-demand_holder_idiom from wikipedia
Since the class does not have any
static
variables to initialize, the initialization completes trivially.The static class definition
LazyHolder
within it is not initialized until the JVM determines that LazyHolder must be executed.The static class
LazyHolder
is only executed when the static methodgetInstance
is invoked on the class Singleton, and the first time this happens the JVM will load and initialize theLazyHolder
class.This solution is thread-safe without requiring special language constructs (i.e.
volatile
orsynchronized
).Declaring the variable as
volatile
guarantees that all accesses to it actually read its current value from memory.Without
volatile
, the compiler may optimize away the memory accesses and keep its value in a register, so only the first use of the variable reads the actual memory location holding the variable. This is a problem if the variable is modified by another thread between the first and second access; the first thread has only a copy of the first (pre-modified) value, so the secondif
statement tests a stale copy of the variable's value.