A recent question here had the following code (well, similar to this) to implement a singleton without synchronisation.
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
Now, I think understand what this is doing. Since the instance is static final
, it's built long before any threads will call getInstance()
so there's no real need for synchronisation.
Synchronisation would be needed only if two threads tried to call getInstance()
at the same time (and that method did construction on first call rather than at "static final"
time).
My question is therefore basically: why then would you ever prefer lazy construction of the singleton with something like:
public class Singleton {
private Singleton() {}
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
My only thoughts were that using the static final
method may introduce sequencing issue as in the C++ static initialisation order fiasco.
First off, does Java actually have this problem? I know order within a class is fully specified but does it somehow guarantee consistent order between classes (such as with a class loader)?
Secondly, if the order is consistent, why would the lazy construction option ever be advantageous?
A class is initialized when it's accessed at runtime. So init order is pretty much the execution order.
"Access" here refers to limited actions specified in the spec. The next section talks about initialization.
What's going on in your first example is equivalently
( Once initialized, the sync block becomes useless; JVM will optimize it off. )
Semantically, this is not different from the 2nd impl. This doesn't really outshine "double checked locking", because it is double checked locking.
Since it piggybacks on class init semantics, it only works for static instances. In general, lazy evaluation is not limited to static instances; imagine there's an instance per session.
The patern that you described works for two reasons
So you do perform lazy initialization in a thread safe and efficient way. This pattern is better alternative to double lock (not working) solution to synchronized lazy init.
No.
SingletonHolder
class will be loaded only when you invokeSingletonHolder.INSTANCE
for the very first time.final
Object will become visible to other threads only after it is fully constructed. Such lazy initialization is calledInitialization on demand holder idiom
.It does, but to a lesser degree than in C++:
If there is no dependency cycle, the static initialization occurs in the right order.
If there is a dependency cycle in the static initialization of a group of classes, then the order of initialization of the classes is indeterminate.
However, Java guarantees that default initialization of static fields (to null / zero / false) happens before any code gets to see the values of the fields. So a class can (in theory) be written to do the right thing irrespective of the initialization order.
Lazy initialization is useful in a number of situations:
When the initialization has side effects that you don't want to happen unless the object is actually going to be used.
When the initialization is expensive, and you don't want it to waste time doing it unnecessarily ... or you want more important things to happen sooner (e.g. displaying the UI).
When the initialization depends on some state that is not available at static initialization time. (Though you need to be careful with this, because the state might not be available when lazy initialization gets triggered either.)
You can also implement lazy initialization using a synchronized
getInstance()
method. It is easier to understand, though it makes thegetInstance()
fractionally slower.The only correct singletone in Java can be declared not by class, but by enum:
The use is as:
All other ways do not exclude repeated instantiation through reflection or if the source of class is directly present in the app source. Enum excludes everything. ( The final clone method in Enum ensures that enum constants can never be cloned )
Not quite. It is built when the
SingletonHolder
class is initialized which happens the first timegetInstance
is called. The classloader has a separate locking mechanism, but after a class is loaded, no further locking is needed so this scheme does just enough locking to prevent multiple instantiation.Java does have a problem where a class initialization cycle can lead to some class observing another class's static finals before they are initialized (technically before all static initializer blocks have run).
Consider
Running C prints
But in the idiom you posted, there is no cycle between the helper and the singleton so there is no reason to prefer lazy initialization.