I have explained the basics of singleton pattern here https://vtkrishn.wordpress.com/2010/03/26/singleton-pattern-revisited/
The design goes like this
1) private constructor
2) static method to return the single objects
In this post I am going to explain some additional restrictions on this pattern
1) Lazy initialization with double lock mechanism
2) Early initialization
3) Serialization
4) ClassLoaders
5) Restrict Cloning
Lazy instantiation using double locking mechanism
The standard implementation shown in the code above is a thread safe implementation, but it’s not the best thread-safe implementation because synchronization is very expensive when we are talking about the performance. We can see that the synchronized method getInstance does not need to be checked for synchronization after the object is initialized. If we see that the singleton object is already created we just have to return it without using any synchronized block. This optimization consist in checking in an un-synchronized block if the object is null and if not to check again and create it in an synchronized block. This is called double locking mechanism.
In this case case the singleton instance is created when the getInstance() method is called for the first time. This is called lazy instantiation and it ensures that the singleton instance is created only when it is needed.
//Lazy instantiation using double locking mechanism.
class Singleton
{
private static Singleton m_instance;
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
if (m_instance == null)
{
synchronized(Singleton.class)
{
if (m_instance == null)
{
System.out.println("getInstance(): First time getInstance was invoked!");
m_instance = new Singleton();
}
}
}
return m_instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does something!");
}
}
Early instantiation using implementation with static field
In the following implementattion the singleton object is instantiated when the class is loaded and not when it is first used, due to the fact that the m_instance member is declared static. This is why in this implementation we don’t need to syncronize any portion of the code. The class is loaded once this guarantee the unicity of the object
//Early instantiation using implementation with static field.
class Singleton
{
private static Singleton m_instance = new Singleton();
private Singleton()
{
System.out.println("Singleton(): Initializing Instance");
}
public static Singleton getInstance()
{
return m_instance;
}
public void doSomething()
{
System.out.println("doSomething(): Singleton does something!");
}
}
Serialization
If the Singleton class implements the java.io.Serializable interface, when a singleton is serialized and then deserialized more than once, there will be multiple instances of Singleton created. In order to avoid this the readResolve method should be implemented. See Serializable () and readResolve Method () in javadocs.
public class Singleton implements Serializable {
...
// This method is called immediately after an object of this class is deserialized.
// This method returns the singleton instance.
protected Object readResolve() {
return getInstance();
}
}
ClassLoaders
If you have multiple classloaders(possibilities in case of servlet container) then the patterns will allow for multiple instances to be created which is not expected
To overcome this you have to have the custom implementation like
private static Class getClass(String classname)
throws ClassNotFoundException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if(classLoader == null)
classLoader = Singleton.class.getClassLoader();
return (classLoader.loadClass(classname));
}
}
Restrict Cloning
You can overcome cloning of the singleton object by explicitly throwing cloneNotSupportedException
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
If we try to access the above singleton object using reflection then you will get
Exception in thread "Main Thread" java.lang.IllegalAccessException: Class com.example.thread.Main can not access a member of class com.simple.NormalClass with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.Class.newInstance0(Class.java:349)
at java.lang.Class.newInstance(Class.java:308)
at com.example.thread.Main.main(Main.java:10)
if you are using java 1.5 and above you can use enum type which takes care of all the above
public enum Singleton{
INSTANCE;
public static void print(){
System.out.println("hi");
}
public class Main{
public static void main(String[] args) {
Singleton.INSTANCE.print();
}
}
}
Like this:
Like Loading...