After going through a couple job interviews, I quickly realized that there are many differing “opinions” (yes even among seasoned Java programmers) about the best way to initialize a singleton class. For the record, there are really only two fundamental ways of initializing a singleton properly in java: eager or lazy. Then there is a neat trick to try to get the best of both worlds so that makes a total of three. Depending on the person you talk to, one of these methods may be preferred over the others but all three listed below are thread safe.
Eager Initialization
In eager initialization, the singleton is instantiated when the programs starts whether or not it gets used. The problem with this approach is that valuable resources are allocated whether or not they ever get used. If the singleton has a large memory footprint, this may not be a good choice.
Example 1. Eager Initialization
public class Singleton {
// Eager initialization happens here.
static private Singleton instance = new Singleton();
// Prevent instantiation by public.
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
Eager initialization relies on the fact that the JVM will initialize the class members upon loading the class. And the class is loaded when it is first referenced.
Lazy Initialization
On the other end of the spectrum, we have lazy initialization which the object only get instantiated on the first time the getInstance() method is called. This has the advantage of not allocating the resources unless it is actually needed.
The problem with this approach is that the getInstance() method needs to be synchronized. Therefore there is a performance hit when acquiring the singleton.
Example 2. Lazy Initialization
public class Singleton {
static private Singleton instance = null;
// Prevent instantiation by public.
private Singleton() {
}
synchronized public static Singleton getInstance() {
if (instance == null) {
// Lazy initialization happens here
// on the first call to this method.
instance = new Singleton();
}
return instance;
}
}
Do not try to circumvent the synchronized method by using a DCL (double check locking) mechanism as it does not work with the java memory model. Read more about that by following the resources links below.
Initialize-on-demand holder class idiom
There is one final way to get the best of both worlds and that is to use “Initialize-on-demand holder class” idiom which can be found in “Effective Java” by Joshua Bloch. This method relies on the JVM only intializing the class members upon first reference to the class. In this case, we have a inner class that is only referenced within the getInstance() method. This means SingletonHolder will get initialized on the first call to getInstance().
Example 3. Initialize-on-demand
public class Singleton {
// Prevent instantiation by public.
private Singleton() {
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
/**
* Singleton implementation helper.
*/
private static class SingletonHolder {
// This gets initialized on first reference
// to SingletonHolder.
static final Singleton instance = new Singleton();
}
}
Now the singleton object will not get allocated until it is used and we did not need to incur the overhead of a synchronized method call.
Happy programming,
Chiao
References and Resources
For initialize on demand, isn’t there the possibility that more than one thread may call getInstance() at the same time ?
Yes, multiple threads can call getInstance() at the same time. But just like Eager Initialization, the thread safety comes from the fact that the singleton instance is ultimately held in a static variable. The JVM guarantees that static variables are only initialized once by the classloader, thus insuring that all threads calling getInstance() will return the same instance of the variable.
The advantage for initialize-on-demand idiom is that the static variable is inside an inner class. The main Singleton class does not contain any static variables so eager instantiation will not take place.
So if you have the same implementation as Initialize-on-demand with the difference being that class Singleton declares a static variable, than this approach wont work and it will not be thread safe ? For example:
public class Singleton{
private static final int example = 0; //static variable declared just for example
private Singleton(){ }
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder {
static final Singleton instance = new Singleton();
}
Thanks for your response.
It will work either way. Any static variables inside the class will be guaranteed to be initialized only once and before they are used. Having other static variables inside the Singleton class does not affect the static “instance” variable inside the inner class. Of course, your variable “example” may not be thread-safe depending on how you use it. But “instance” is still thread safe.
how does this mechanism handle :
1. loading the singleton from multiple classloaders?
2. serializing & deserializing?
Wouldnt these still result in multiple instances?