In our previous article about Singleton Design Pattern, we have discussed about basics of its working and design. Today we are adding more points to it.
While implementing singleton, we need to take care that it should work well in multiple thread environment. So one option is to initialize the instance eagerly at the time of declaring the variable. But if we want to initialize the variable lazily, i.e. only when it is required, then we can make the method 'getSharedInstance' synchronized. But that will slow down the operations in every request. But we need synchronization only if instance is null and we need to create it.
So one approach could be to use double 'null' check as given below:
getSharedInstance()
{
// first check to make sure that synchronization comes in effect only if instance is null
if (instance == null )
{
// synchronizing to avoid access my multiple threads
synchronized (this)
{
// check again if instance is not null, as first check of not null may be passed by more than one thread
if (instance == null)
{
instance = new Instance();
}
}
}
return instance;
}
While implementing singleton, we need to take care that it should work well in multiple thread environment. So one option is to initialize the instance eagerly at the time of declaring the variable. But if we want to initialize the variable lazily, i.e. only when it is required, then we can make the method 'getSharedInstance' synchronized. But that will slow down the operations in every request. But we need synchronization only if instance is null and we need to create it.
So one approach could be to use double 'null' check as given below:
getSharedInstance()
{
// first check to make sure that synchronization comes in effect only if instance is null
if (instance == null )
{
// synchronizing to avoid access my multiple threads
synchronized (this)
{
// check again if instance is not null, as first check of not null may be passed by more than one thread
if (instance == null)
{
instance = new Instance();
}
}
}
return instance;
}
But in above approach, we are still synchronizing a code block, and checking the instance for 'null' twice. There can be another better approach as given below:
public class SingletonObject
{
public static SingletonObject getSharedInstance ()
public static SingletonObject getSharedInstance ()
{
return SingletonHolder.sharedInstance;
}
private static class SingletonHolder
{
static SingletonObject sharedInstance = new SingletonObject();
}
}
Here no synchronization is required in code. The instance will be initialized lazily only when request will hit getSharedInstance method for the first time, as inner static class will be initialized then.
With these approaches, you need to take care of few points like
- Cloning should not be supported
- Constructor of class should be private
- Serialization should be controlled, i.e. we should override readResolve method to return the shared instance.
But later 'Joshua Bloch' has proposed another approach, termed as best approach for implementing Singleton Patter. This is to use 'enum' for implementation. Example is given below:
// Enum Singleton
public enum SingletonObject
{
SHAREDINSTANCE;
public void someMethod()
{
.....
}
}
And it is done. Now you can use it like
SingletonObject.SHAREDINSTANCE.someMethod()
It is perfectly thread safe without any double check for null or synchronization. Check in serialization methods are also not required, because Enum are serialization specially in Java by just writing their names in stream.
And it is done. Now you can use it like
SingletonObject.SHAREDINSTANCE.someMethod()
It is perfectly thread safe without any double check for null or synchronization. Check in serialization methods are also not required, because Enum are serialization specially in Java by just writing their names in stream.
With this approach, there is no chance to have more than one instance of object with any of the hook. From Joshua book -
This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks. While this approach has yet to be widely adopted, a single-element enum type is the best way to implement a singleton.