Singleton pattern is a design pattern that restricts the instantiation of a class to one object, and to provide a global point of access to it.
Sometimes you need to have only one instance of your class in JVM. For example, in a system there should be only one window manager (or only a file system or only a print spooler).
Implementation
Note: Singleton object is not created until we need it and call getInstance() method. This is called lazy instantiation.public class Singleton { private static Singleton obj; // private constructor force to use // getInstance() to create Singleton object private Singleton() {} public static Singleton getInstance() { if (obj == null) { obj = new Singleton(); } return obj; } }private constructor ensure only one way of instantiating the class through the getInstance() method. Static getInstance() method can call without instantiating the class. The first time getInstance() is called it creates a new Singleton object(Lazy instantiation) and after that it will just return the same object.
Specific problems and implementation
Thread-safe implementation for multi-threading use.
A robust singleton implementation should work in any conditions. This is why we need to ensure it works when multiple threads use it. As seen in the previous example singleton can be used specifically in multi-threaded application to make sure the reads/writes are synchronized.
class Singleton { private static Singleton obj; private Singleton() {} // Only one thread can execute at a time public static synchronized Singleton getInstance() { if (obj == null) { obj = new Singleton(); } return obj; } }Here using synchronized makes sure that only one thread at a time can execute getInstance().
The main disadvantage of this method is that while creating the singleton object is expensive and may decrease the performance of your program. However if performance is not critical for your application then this method is clean and simple.
Double locking checking
The standard implementation shown in the above code 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 unsynchronized block if the object is null and if not, check it again and create it in a synchronized block. This is called double locking mechanism.
class Singleton { private static Singleton obj; private Singleton() {} public static Singleton getInstance() { if (obj == null) { // make thread safe synchronized (Singleton.class) { // double check here, cause multiple thread can reach here if (obj == null) obj = new Singleton(); } } return obj; } }Early instantiation using implementation with static field
singleton object is instantiated when the class is loaded and not when it is first used, JVM initialize the static member when the class is loaded. This is why we don't need to synchronize any portion of the code. Use this approach only when your singleton class is light and is used throughout the execution of your program.
class Singleton { private static Singleton obj = new Singleton(); private Singleton() {} public static Singleton getInstance() { return obj; } }
Serialization
If Singleton class implements Serializable interface, when a Singleton class is serialized and then deserialize more than once, there will be multiple instance of Singleton object will be in JVM. In order to avoid this readResolve() method should be implemented.
Understand it by example
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; public class Singleton implements Serializable, Runnable { private static final long serialVersionUID = 1L; private static Singleton obj = null; private int x; @Override public String toString() { return "Singleton [x= " + x + "]"; } private Singleton() {} public static Singleton getInstance() { if (obj == null) { synchronized (Singleton.class) { if (obj == null) obj = new Singleton(); } } return obj; } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { System.out.println("In ReadObject()"); // Read the non-static and non-transient fields of the current class // from this stream. // This may only be called from the readObject method of the class being // deserialized. // It will throw the NotActiveException if it is called otherwise ois.defaultReadObject(); obj = this; // rather than creating new instance, assign current object // to obj } private Object readResolve() { System.out.println("In readResolve()"); return obj; } public static void main(String[] args) throws IOException, ClassNotFoundException { Singleton object1 = Singleton.getInstance(); object1.x = 22; OutputStream fout = new FileOutputStream("serial.txt"); ObjectOutput oout = new ObjectOutputStream(fout); System.out.println("Serialization process has started, serializing objects..."); oout.writeObject(getInstance()); System.out.println("Object state at time of Serialization : " + getInstance()); fout.close(); oout.close(); System.out.println("Object Serialization completed."); object1.x = 33; System.out.println("Object state modified after Serialization : " + getInstance()); Thread t1 = new Thread(object1); Thread t2 = new Thread(object1); Thread t3 = new Thread(object1); t1.start(); // modified object here also object1.x = 45; t2.start(); // modified object here also object1.x = 50; t3.start(); } @Override public void run() { InputStream fin; System.out.println("Thread Name " + Thread.currentThread().getName()); try { fin = new FileInputStream("serial.txt"); ObjectInput oin = new ObjectInputStream(fin); System.out.println("\nDeSerialization process has started, displaying objects..."); oin.readObject(); System.out.println("Object state after DeSerialization : " + getInstance()); fin.close(); oin.close(); System.out.println("Object DeSerialization completed."); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }Output of the above program:
Serialization process has started, serializing objects... Object state at time of Serialization : Singleton [x= 22] Object Serialization completed. Object state modified after Serialization : Singleton [x= 33] Thread Name Thread-0 Thread Name Thread-1 Thread Name Thread-2 DeSerialization process has started, displaying objects... DeSerialization process has started, displaying objects... DeSerialization process has started, displaying objects... In ReadObject() In ReadObject() In ReadObject() In readResolve() In readResolve() In readResolve() Object state after DeSerialization : Singleton [x= 22] Object state after DeSerialization : Singleton [x= 22] Object DeSerialization completed. Object state after DeSerialization : Singleton [x= 22] Object DeSerialization completed. Object DeSerialization completed.Here we are Serializing Singleton class such that object returned by Deserialization process is in same state as it was during Serialization time (regardless of any change made to it after Serialization). Defining readResolve() method ensures that we don't break singleton pattern during DeSerialization process.
private Object readResolve() throws ObjectStreamException { return obj; }Can you Serialize Singleton class such that object returned by Deserialization process is in same state as it was during Serialization time (regardless of any change made to it after Serialization)?
Yes, Above code also explain about it. we can get the same state of object as it was during serialization time(regardless of any change made to it after serialization).
Very clear explanation!
ReplyDeletesuper explanation...we like to see more such post....
ReplyDeleteThanks Avijit
DeleteWell explained . Great article on singleton pattern . There is also good singleton pattern example visit Singleton class example
ReplyDelete