Dictionary meaning of Singleton: a single person or thing of the kind under consideration.
Java singleton design pattern is considered as one of the simplest design patters. It comes under the Creational Design Pattern category.
Singleton design pattern simply states that only single object should be created and it will be used by all other classes.
Singleton design pattern is commonly used in logging, caching, driver’s objects, thread pools etc. It is also used in other design patterns like Abstract Factory, Facade, Builder, Prototype etc.
How to create Singleton design pattern?
Singleton design pattern can be implemented in different ways but the concept is same for all.
- Private constructor: Private constructor is used to prevent instantiation of the class from other classes.
- Private static variable: Private static variable will contain the instance of the class.
- Public static method: Public static method is the global access point for other classes to get the instance of the singleton class. It will returns the instance of the singleton class.
Let’s discuss implementation of Singleton design pattern with different approaches.
Eager initialization
In case of eager initialization instance of the singleton class is created at the time of class loading.
Example:
package com.w3spoint; public class SingletonTest { private static final SingletonTest instance = new SingletonTest(); //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} public static SingletonTest getInstance(){ return instance; } } |
Problem with eager initialization approach:
As we discussed that instance of the singleton class is created at the time of class loading. So there may be the cases when client application is not using the object but the object is still created. Other problem with the eager initialization approach is that we do not have any way to handle the exceptions.
Static block initialization
Static block initialization approach to implement singleton design pattern is almost same as eager initialization approach with exception handling facility.
Example:
package com.w3spoint; public class SingletonTest { private static final SingletonTest instance; //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} //Static block initialization static{ try{ instance = new SingletonTest(); }catch(Exception e){ throw new RuntimeException("Exception occured."); } } public static SingletonTest getInstance(){ return instance; } } |
Problem with static block initialization approach:
It solve the exception handling problem with eager initialization approach but object creation before its being used is still there.
Lazy Initialization
Lazy initialization approach to implement singleton design pattern solve the problem of object creation before its being used. In this approach we will create the instance in the global access method.
Example:
package com.w3spoint; public class SingletonTest { private static SingletonTest instance; //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} public static SingletonTest getInstance(){ if(instance == null){ instance = new SingletonTest(); } return instance; } } |
Problem with lazy initialization approach:
Lazy initialization approach may not work and may cause issues in multithreading environment. As we can see there is nock on the getInstance() method, so if two threads are accessing the getInstance() method at same time they can get two different objects which will break the singleton concept.
Thread Safe Approach
Thread safe approach to implement singleton design pattern will solve the multithreading issue. We have to create a thread-safe singleton class for which we can make the global access method. In this case when one thread executing the getInstance() method other threads have to wait. We can also use synchronized block which is a much better option.
Example with synchronized method
package com.w3spoint; public class SingletonTest { private static SingletonTest instance; //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} public static synchronized SingletonTest getInstance(){ if(instance == null){ instance = new SingletonTest(); } return instance; } } |
Example with synchronized block
package com.w3spoint; public class SingletonTest { private static SingletonTest instance; //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} //synchronized block with double checked locking principle public static SingletonTest getInstance(){ if(instance == null){ synchronized (SingletonTest.class) { if(instance == null){ instance = new SingletonTest(); } } } return instance; } } |
Bill Pugh Singleton Implementation
It is the most widely used approach to implement singleton design pattern. It uses private inner static helper class to create singleton class. Inner static class will contains the singleton class object. It will not be loaded with the singleton class, it will be loaded when getInstance() method is invoked first time.
Note: Bill Pugh Singleton implementation approach doesn’t require synchronization.
Example:
package com.w3spoint; public class SingletonTest { //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} private static class SingletonHelper{ private static final SingletonTest INSTANCE = new SingletonTest(); } public static SingletonTest getInstance(){ return SingletonHelper.INSTANCE; } } |
Using Reflection to destroy Singleton Pattern
According to Java Docs: Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
We can use reflection to destroy the all above approaches to implement singleton design pattern.
Example:
package com.w3spoint; import java.lang.reflect.Constructor; class SingletonTest { private static final SingletonTest instance = new SingletonTest(); //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} public static SingletonTest getInstance(){ return instance; } } public class SingletonTestWithReflection { public static void main(String[] args) { SingletonTest instance1 = SingletonTest.getInstance(); SingletonTest instance2 = null; try { Constructor[] constructors = SingletonTest.class.getDeclaredConstructors(); for (Constructor constructor : constructors) { constructor.setAccessible(true); instance2 = (SingletonTest) constructor.newInstance(); break; } } catch (Exception e) { e.printStackTrace(); } System.out.println(instance1.hashCode()); System.out.println(instance2.hashCode()); } } |
Output:
366712642 1829164700 |
Note: You can clearly see that hash code of two objects are different which breaks the singleton design pattern concept. To overcome this problem we should use Enum to implement Singleton design pattern because Enum values are instantiated only once.
Serialization in Singleton Design Pattern
We can serialize a singleton object but in case of deserialization, it will return a new object which will breaks the singleton design pattern concept. To overcome this problem we need to provide the implementation on readResolve() method which enforces the singleton pattern.
package com.w3spoint; import java.io.Serializable; public class SingletonTest implements Serializable { //Private constructor to prevent instantiation of the class from other classes. private SingletonTest(){} private static class SingletonHelper{ private static final SingletonTest INSTANCE = new SingletonTest(); } public static SingletonTest getInstance(){ return SingletonHelper.INSTANCE; } protected Object readResolve() { return getInstance(); } } |