Singleton Design Pattern
We need to create a class which can have only one instance at any time.
Solution 1:
Let's create the object when we need it, not at the time of loading the class.
Solution 2(with Lazy loading):
When multiple threads reach "Line : 5" at the same time, multiple objects can be created.
Solution 3: Using synchronized method
Even to check the 'not null' condition, all threads need to wait, to acquire lock on that class. As the method is synchronized, we are paying the cost of synchronization for every thread invocation of the method, even though it is only required on the first thread invocation.
synchronize only the instance creation not the whole method.
Solution 4: Using synchronized block
There is a problem in the above solution. Let's say there are two threads A and B. Thread A and thread B executes "Line: 5" at the same time. As the singleton object is yet to be instantiated, both satisfies the null check and enters into "Line: 6". As we are using synchronized block here, only one thread i.e. first thread (say Thread A) gets the lock on class and creates the singleton object, Thread B wait outside at "Line:6" until Thread A releases the lock. Once it releases the lock, Thread B also gets the lock and creates one more object. It can be resolved by checking null one more time inside the synchronized block.
Solution 5: Using Double-checked locking
It looks like, it is a perfect solution. No,it is not.
Note : Our Java compiler is free to reorder the instructions.
Let's say there are two threads A and B.Imagine that thread A is inside the synchronized block, executing the statement singleton = new MySingleton(); while thread B is just entering getMySingleton(). Consider the effect on memory of this initialization. Memory for the new MySingleton object will be allocated; the constructor for MySingleton will be called, initializing the member fields of the new object; and the field singleton of MySingleton will be assigned a reference to the newly created object.
However, since thread B is not executing inside a synchronized block, it may see these memory operations in a different order than the one thread A executes. It could be the case that B sees these events in the following order (and the compiler is also free to reorder the instructions like this): allocate memory, assign reference to singleton, call constructor. Suppose thread B comes along after the memory has been allocated and the singleton field is set, but before the constructor is called. It sees that singleton is not null, skips the synchronized block, and returns a reference to a partially constructed singleton! Needless to say, the result is neither expected nor desired.
Reference:: From JavaWorld
Solution 6: Using Volatile
volatile ensures that the system will not allow a write of a volatile to be reordered with respect to any previous read or write, and a read of a volatile cannot be reordered with respect to any following read or write
Usually you sould not implement eaither Serializable or Cloneable while wrinting a singleton class.
Even if your singleton class implments Cloneable, here is how you can still make sure that there will be only one object for your single tom class.
Just override the clone method to throw an exception like below.
Solution 7: can't be cloned.
Sometimes in distributed systems, we need to implement Serializable interface in Singleton class so that we can store it’s state in file system and retrieve it at later point of time. Here is a small singleton class that implements Serializable interface also.
To make a singleton class serializable, it is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created
readResolve works only when all fields are transient.
Solution 8: using readResolve().
After all here is the new simple singleton which can handle lazy inititialization, serialization and they are thread safe. Newly introduced in JAVA 1.5.
Solution 9: using ENUM.
Solution 1:
public class MySingleton {
private static MySingleton singleton= new MySingleton();
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
return singleton;
}
}
Let's create the object when we need it, not at the time of loading the class.
Solution 2(with Lazy loading):
public class MySingleton { // Line : 1
private static MySingleton singleton=null; // Line : 2
private MySingleton(){ System.out.println( "Object Created" ); } // Line : 3
public static MySingleton getMySingleton(){ // Line : 4
if(singleton == null) // Line : 5
{
singleton = new MySingleton(); // Line : 6
}
return singleton; // Line : 7
}
}
When multiple threads reach "Line : 5" at the same time, multiple objects can be created.
Solution 3: Using synchronized method
public class MySingleton {
private static MySingleton singleton=null;
private MySingleton(){ System.out.println( "Object Created" ); }
public static synchronized MySingleton getMySingleton(){
if(singleton == null)
{
singleton = new MySingleton();
}
return singleton;
}
}
Even to check the 'not null' condition, all threads need to wait, to acquire lock on that class. As the method is synchronized, we are paying the cost of synchronization for every thread invocation of the method, even though it is only required on the first thread invocation.
synchronize only the instance creation not the whole method.
Solution 4: Using synchronized block
public class MySingleton { // Line : 1
private static MySingleton singleton=null; // Line : 2
private MySingleton(){ System.out.println( "Object Created" ); } // Line : 3
public static MySingleton getMySingleton(){ // Line : 4
if(singleton == null) // Line : 5
{
synchronized (MySingleton.class) { // Line : 6
singleton = new MySingleton(); // Line : 7
}
}
return singleton; // Line : 8
}
}
There is a problem in the above solution. Let's say there are two threads A and B. Thread A and thread B executes "Line: 5" at the same time. As the singleton object is yet to be instantiated, both satisfies the null check and enters into "Line: 6". As we are using synchronized block here, only one thread i.e. first thread (say Thread A) gets the lock on class and creates the singleton object, Thread B wait outside at "Line:6" until Thread A releases the lock. Once it releases the lock, Thread B also gets the lock and creates one more object. It can be resolved by checking null one more time inside the synchronized block.
Solution 5: Using Double-checked locking
public class MySingleton {
private static MySingleton singleton=null;
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
if(singleton == null)
{
synchronized (MySingleton.class) {
if(singleton == null)
{
singleton = new MySingleton();
}
}
}
return singleton;
}
}
It looks like, it is a perfect solution. No,it is not.
Note : Our Java compiler is free to reorder the instructions.
Let's say there are two threads A and B.Imagine that thread A is inside the synchronized block, executing the statement singleton = new MySingleton(); while thread B is just entering getMySingleton(). Consider the effect on memory of this initialization. Memory for the new MySingleton object will be allocated; the constructor for MySingleton will be called, initializing the member fields of the new object; and the field singleton of MySingleton will be assigned a reference to the newly created object.
However, since thread B is not executing inside a synchronized block, it may see these memory operations in a different order than the one thread A executes. It could be the case that B sees these events in the following order (and the compiler is also free to reorder the instructions like this): allocate memory, assign reference to singleton, call constructor. Suppose thread B comes along after the memory has been allocated and the singleton field is set, but before the constructor is called. It sees that singleton is not null, skips the synchronized block, and returns a reference to a partially constructed singleton! Needless to say, the result is neither expected nor desired.
Reference:: From JavaWorld
Solution 6: Using Volatile
volatile ensures that the system will not allow a write of a volatile to be reordered with respect to any previous read or write, and a read of a volatile cannot be reordered with respect to any following read or write
public class MySingleton {
private static volatile MySingleton singleton=null;
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
if(singleton == null)
{
synchronized (MySingleton.class) {
if(singleton == null)
{
singleton = new MySingleton();
}
}
}
return singleton;
}
}
Usually you sould not implement eaither Serializable or Cloneable while wrinting a singleton class.
Even if your singleton class implments Cloneable, here is how you can still make sure that there will be only one object for your single tom class.
Just override the clone method to throw an exception like below.
Solution 7: can't be cloned.
public class MySingleton implements Cloneable {
private static volatile MySingleton singleton=null;
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
if(singleton == null)
{
synchronized (MySingleton.class) {
if(singleton == null)
{
singleton = new MySingleton();
}
}
}
return singleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cloning of this class is not allowed");
}
}
Sometimes in distributed systems, we need to implement Serializable interface in Singleton class so that we can store it’s state in file system and retrieve it at later point of time. Here is a small singleton class that implements Serializable interface also.
To make a singleton class serializable, it is not sufficient merely to add implements Serializable to its declaration. To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created
readResolve works only when all fields are transient.
Solution 8: using readResolve().
import java.io.ObjectStreamException;
import java.io.Serializable;
public class MySingleton implements Cloneable,Serializable {
private static volatile MySingleton singleton=null;
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
if(singleton == null)
{
synchronized (MySingleton.class) {
if(singleton == null)
{
singleton = new MySingleton();
}
}
}
return singleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cloning of this class is not allowed");
}
protected Object readResolve() throws ObjectStreamException {
return singleton;
}
}
After all here is the new simple singleton which can handle lazy inititialization, serialization and they are thread safe. Newly introduced in JAVA 1.5.
Solution 9: using ENUM.
public class MySingleton {
private static enum SingletonEnum {
INSTANCE;
private static final MySingleton singleton = new MySingleton();
public MySingleton getSingleton() {
return singleton;
}
}
private MySingleton(){ System.out.println( "Object Created" ); }
public static MySingleton getMySingleton(){
return SingletonEnum.INSTANCE.getSingleton();
}
}
Review Comments:
ReplyDeleteIn example 8, you have removed volatile, the variable should be declared as.
public static transient volatile MySingleton singleton = null
Please revise.
Thanks M.V.K for pointing out my mistake. There is one more mistake in the same line.
DeleteWe don't need to define a variable as transient along with static. Static fields are always transient. I will be updating both.
nice post
ReplyDeletebest devops training in chennai
devops training in chennai
best hadoop training in chennai
best hadoop training in omr
hadoop training in sholinganallur
best java training in chennai
best python training in chennai