Technically the outer if statement is not required. It's an optimisation. If we remove that, it's a little bit easier to see what's going on.
public Singleton get() {
synchronized(this) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
In this example, we know - thanks to synchronisation - that for this instance of the factory only a single thread can be in the synchronized
block at any one time. It's then safe to check-then-act. instance
cannot be initialised twice.
However, there's a problem with this implementation. Every single time we try to get the instance, we need to synchronise. This really doesn't take maximum advantage of currency. It might block other threads unnecessarily.
That's why we add an extra check. The may be more than one thread trying to do initialisation simultaneously but after this brief period of time we should never need to do the synchronisation again.
public Singleton get() {
if (instance == null) {
//instance may actually have been created now by another thread
synchronized(this) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
Is the store operation atomic here?
Yes. Assignment of references in Java is atomic.