Singleton Design Patterns: Singleton pattern comes under creational patterns. Design patterns are specification for designing repeatable solutions for specific type of problems. Singleton is a design pattern to solve problems which require only a single instance of any class. For singleton class only one and only one object can be created per JVM.
There are multiple ways to implement singleton pattern in your application.
Eager Initialization:
public class SingletonClass{
Eager initialization mechanism of creating singleton class is very simple and efficient. But it’s not a good idea to use eager initialization if creating instance is very costly operation. Because there might be case object in not being use ate the time of loading singleton class, while it will be created at the time of loading of the class.
There is another way to deal with it, Lazy initialization.
Lazy Initialization: In this mechanism of creating singleton object, object creation operation is delayed and actually created only when first referenced.
To prevent multiple thread accessing getInstance() method we can modify above implementation. This is called double-check locking mechanism.
Lazy Initialization with double-check locking:
One another approach using ENUM is preferred way for implementing Singleton behavior.
public enum SingletonClass{
You might know, enum can have well-defined behavior like any other class. So we can use enum for implementing Singleton behavior. This is very concise, and avoid serialization issues as well. Enum by its nature provides guarantee against multiple instantiation, even in serialization or reflection attacks. According to Joshua Bloch “single-element enum type is the best way to implement a singleton.”
Limitation: Singleton class are very hard to test, it is impossible to mock object until it implement any interface which that can be used as its type.
Serialization and Singleton: Suppose we have a serializable class and we need to make it singleton. Any above discussed mechanism can be used to make it singleton. But suppose we have serialized a class and again deserialize it. Deserialization results in a new object. So there would be two object present in JVM, and that will break our singleton behavior. Preventing deserialization from creating new object we would have to make some changes to above implementations.
Have a look on this implementation, you might notice one more method readResolve() is added. During deserialization process this method will be called before creating new object. Here you can provide logic according to your need, like if you do not want to allow deserializing object you can throw an exception saying deserialization is not allowed or you can call getInstance() so that object must be created by a standard process.
Cloneable and Singleton: There might be another case where you want to make a cloneable class Singleton. Above all implementations will not be sufficient for handling singleton behavior for a cloneable class. Because clone on the object will result in one another object and our singleton behavior will be broken again.
Let’s modify our last implementation for keeping our singleton behavior even in case of Cloneable.
So the latest implementation for Singleton behavior will provide you full proof Singleton object per JVM.
There are multiple ways to implement singleton pattern in your application.
Eager Initialization:
public class SingletonClass{
private SingletonClass(){}
private static final SingletonClass INSTANCE = new SingletonClass();
public static SingletonClass getInstance(){
return INSTANCE;
}
}Eager initialization mechanism of creating singleton class is very simple and efficient. But it’s not a good idea to use eager initialization if creating instance is very costly operation. Because there might be case object in not being use ate the time of loading singleton class, while it will be created at the time of loading of the class.
There is another way to deal with it, Lazy initialization.
Lazy Initialization: In this mechanism of creating singleton object, object creation operation is delayed and actually created only when first referenced.
public class SingletonClass{
private SingletonClass(){}
private static SingletonClass singleton;
public static SingletonClass getInstance(){
if(singleton == null){
singleton = new SingletonClass();
}
return singleton;
}
}
So this implementation seems good and fast because of lazy initialization and I would work very well in single threaded environment. But in multi-threaded environment it can behave unexpectedly. Because multiple thread can enter into getInstance() method and create multiple instances. That will break class’s singleton behavior.To prevent multiple thread accessing getInstance() method we can modify above implementation. This is called double-check locking mechanism.
Lazy Initialization with double-check locking:
public class SingletonClass{
private SingletonClass(){}
private static SingletonClass singleton;
public static SingletonClass getInstance(){
if(singleton == null){
synchronized(SingletonClass.class){
if(singleton == null){
singleton = new SingletonClass();
}
}
}
return singleton;
}
}
Above implementation will work properly in single threaded and multi threaded both environment.One another approach using ENUM is preferred way for implementing Singleton behavior.
public enum SingletonClass{
INSTANCE;
}You might know, enum can have well-defined behavior like any other class. So we can use enum for implementing Singleton behavior. This is very concise, and avoid serialization issues as well. Enum by its nature provides guarantee against multiple instantiation, even in serialization or reflection attacks. According to Joshua Bloch “single-element enum type is the best way to implement a singleton.”
Limitation: Singleton class are very hard to test, it is impossible to mock object until it implement any interface which that can be used as its type.
Serialization and Singleton: Suppose we have a serializable class and we need to make it singleton. Any above discussed mechanism can be used to make it singleton. But suppose we have serialized a class and again deserialize it. Deserialization results in a new object. So there would be two object present in JVM, and that will break our singleton behavior. Preventing deserialization from creating new object we would have to make some changes to above implementations.
public class SingletonClass implements Serializable {
private SingletonClass(){}
private static SingletonClass singleton;
public static SingletonClass getInstance(){
if(singleton == null){
synchronized(SingletonClass.class){
if(singleton == null){
singleton = new SingletonClass();
}
}
}
return singleton;
}
//This method will make sure no other object created during deserialization process if one is already exists in JVM.
private Object readResolve(){
return getInstance();
}
}Have a look on this implementation, you might notice one more method readResolve() is added. During deserialization process this method will be called before creating new object. Here you can provide logic according to your need, like if you do not want to allow deserializing object you can throw an exception saying deserialization is not allowed or you can call getInstance() so that object must be created by a standard process.
Cloneable and Singleton: There might be another case where you want to make a cloneable class Singleton. Above all implementations will not be sufficient for handling singleton behavior for a cloneable class. Because clone on the object will result in one another object and our singleton behavior will be broken again.
Let’s modify our last implementation for keeping our singleton behavior even in case of Cloneable.
public class SingletonClass implements Serializable, Cloneable {
private SingletonClass(){}
private static SingletonClass singleton;
public static SingletonClass getInstance(){
if(singleton == null){
synchronized(SingletonClass.class){
if(singleton == null){
singleton = new SingletonClass();
}
}
}
return singleton;
}
//This method will make sure no other object created during deserialization process if one is already exists in JVM.
private Object readResolve(){
return getInstance();
}
//This method will make sure no other object created during cloning of this object
@Override
public Object clone(){
return getInstance();
}
}
Oberriding clone() method and calling getInstance() method, will make sure object will be created using standard process and threre will be only single instance in JVM.So the latest implementation for Singleton behavior will provide you full proof Singleton object per JVM.
No comments:
Post a Comment