The classic example is:
This is a good solution and design of this class ensures that only one
Singleton
object is ever created. The constructor is declared private
and the getInstance()
method creates only one object In the general case, however, it is not thread-safe. This implementation is fine for single threaded program but when multiple threads are introduced then getInstance() method must be protected.Consider two threads calling the
getInstance()
method concurrently and the following sequence of events.- Thread A calls the
getInstance()
method and determines thatinstance
isnull
at //1.
- Thread A enters the
if
block at //1, but is preempted by thread B before executing the line at //2.
- Thread B calls the
getInstance()
method and determines thatinstance
isnull
at //1.
- Thread B enters the
if
block at //1 and creates a newSingleton
object and assigns the variableinstance
to this new object at //2.
- Thread B returns the
Singleton
object reference at //3.
- Thread B is preempted by thread A.
- Thread A starts where it left off and executes line //2 which results in creation of another
Singleton
object.
- Thread A returns this second object at //3.
The synchronized code mentioned above works correctly for a multithreaded access to getInstance() method. But on carefully looking at the code, you can easily make out that instead of synchronizing whole of getInstance() method, synchronization is required only for the first invocation of the method. Subsequent invocations to getInstance() method does not require synchronization because the first invocation is the only invocation that executes the code at line //2. Synchronization has performance cost associated with it, so in order to make above program more efficient we have following third approach.
SyncSingleton_2 class also exhibits the same problem as was there with the Classic approach.
Consider two threads calling the
getInstance()
method concurrently and the following sequence of events.- Thread A calls the
getInstance()
method and determines thatinstance
isnull
at //1.
- Thread A enters the
if
block at //1, but is preempted by thread B before entering the Synchronized block..
- Thread B calls the
getInstance()
method and determines thatinstance
isnull
at //1.
- Thread B enters the
if
block at //1 and creates a newSingleton
object and assigns the variableinstance
to this new object at //2.
- Thread B returns the
Singleton
object reference at //3.
- Thread B is preempted by thread A.
- Thread A starts where it left off and executes line //2 which results in creation of another
Singleton
object.
- Thread A returns this second object at //3.
To fix the above problem there is solution which require that a second check should be made before creating the object. This method is called Double Checked locking.
The concept behind double-checked locking is that the second check at //2 makes it impossible for two different
SyncSingleton_3
objects to be created.The concept behind Double Check Locking makes it perfect, but this is not the case.The problem with double-checked locking is that there is no guarantee it will work.This is because of Java Platform memory model which allow out-of order writes. We won't be covering that here.
The bottom line is that double-checked locking, in whatever form, should not be used because you cannot guarantee that it will work. So there are only two options left which are as follows.
- First is to synchronize getInstance() method, which we have already covered above.
- Second is to let go synchronization and use static instead, which we will cover now.
In the above scenario StaticSingleton object is not created until call is made to static getInstance() method. This is a good alternative is you donot wish to use synchronisation.The Java specs guarantees that the static initializer will be executed only once, at class load time. There could be an argument that, this would create an object if someone refers to the class or at class loading time even if it is not used and this becomes a valid argument when the object is heavy.
An embedded static final class can defer this as shown below
If someone happens to refer to StaticSingleton.class , the singleton object would not be created unless explicit call to getInstance() method is not done.At that time, SingletonHolder is referred to; its class loads; and its static member instance is instantiated.
There is one thing clear after above discussion on Singleton, that any implementation should be matched carefully to the application at hand.