Singleton pattern is the most common types of patterns used in Java. It is also very common that interviewers ask questions to explain and implement singleton pattern
Lets first define Singleton
Singleton is a class whose only one object can be created.
There are couple of ways to implement Singleton class. Lets see the simplest one first.
The above class has a private constructor to avoid other classes to create objects using new Singleton.
An instance variable instance is created of class Singleton and instantiated. Note that this is a private static variable. That means it can be only accessed from within the class and only from a static method.
To provide this instance to other calsses a static method getInstance() is provided. Note that this is a public method and returns the privately declared an initialized instance variable.
Now lets create a test class to see if only once instance is created.
The above test class gets the instance variable by calling the getInstance() method on the Singleton class. Not since the method is static there is no need to create the instance.
getInstance() is called two times and both the instances firstInstance and secondInstance print the same hashcode. That means both are actually the same objects.
Below is the output
That is it. We have successfully implemented singleton class and tested it.
There is a very small performance issue here. Since the instance variable is initialized when it is declared the Singleton class becomes heavy on the time it is loaded in memory. This is generally not advised.
Here above the instance variable is only declared in class definition and only is instantiated in the getInstance() method. Please note that a null check is provided to check if the instance was already created.
Generally the above 2 implementations satisfies the interviewer. But if the interviewer is smart enough you can expect more questions from him.
This will happen when one thread checks the null condition, got into the if block and is busy in initializing the instnace variable and has not yet initialized it. In the mean time second thread checks for instance==null and since the first thread has not yet instantiated the instance variable, the second thread enter the if block too. Both thread will end up creating 2 instances.
To avoid this, we need to synchronize the getInstance() method.
This will create a lock on the Singleton class and only one thread can at a particular time enter the getInstance() method.
Another way would be to use synchronize block with lock on Singleton class.
To learn more about serialization refer blog Java Synchronization
How can we make sure that when a class is serialized and de-serialized only one instance gets created?
Lets first try to reproduce the problem. Below calss serializes the object in a file and then de-serializes it from the file.
The output is below
Here the hash code printed is different for the serialized and deserialized object. So now we have to unique objects. This violates the Singleton pattern.
The solution here is to override the readResolve() method in the Singleton class. This informs the De-Serialization mechanism that same object instance should be returned.
Lets first define Singleton
Singleton is a class whose only one object can be created.
There are couple of ways to implement Singleton class. Lets see the simplest one first.
1. Eager Initialization
import java.io.Serializable; public class Singleton implements Serializable { // Private static instance of the class private static Singleton instance = new Singleton(); // Private constructor to avoid 'new Singleton()' private Singleton() { } // public static method to create and fetch the single instance public static Singleton getInstance() { return instance; } }
The above class has a private constructor to avoid other classes to create objects using new Singleton.
An instance variable instance is created of class Singleton and instantiated. Note that this is a private static variable. That means it can be only accessed from within the class and only from a static method.
To provide this instance to other calsses a static method getInstance() is provided. Note that this is a public method and returns the privately declared an initialized instance variable.
Now lets create a test class to see if only once instance is created.
public class MyTest { public static void main(String[] args) { //Singleton s = new Singleton(); //this gives a compilation error due to private constructor Singleton firstInstance = Singleton.getInstance(); System.out.println(firstInstance); Singleton secondInstance = Singleton.getInstance(); System.out.println(secondInstance); } }
The above test class gets the instance variable by calling the getInstance() method on the Singleton class. Not since the method is static there is no need to create the instance.
getInstance() is called two times and both the instances firstInstance and secondInstance print the same hashcode. That means both are actually the same objects.
Below is the output
Singleton@2cdf88d2 Singleton@2cdf88d2
That is it. We have successfully implemented singleton class and tested it.
There is a very small performance issue here. Since the instance variable is initialized when it is declared the Singleton class becomes heavy on the time it is loaded in memory. This is generally not advised.
2. Lazy Initialization
Another approach to implement Singleton class is given belowimport java.io.ObjectStreamException; import java.io.Serializable; public class Singleton implements Serializable{ public String name; // Private static instance of the class private static Singleton instance = null; //Private constructor to avoid 'new Singleton()' private Singleton(){ } // public static method to create and fetch the single instance public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } }
Here above the instance variable is only declared in class definition and only is instantiated in the getInstance() method. Please note that a null check is provided to check if the instance was already created.
Generally the above 2 implementations satisfies the interviewer. But if the interviewer is smart enough you can expect more questions from him.
3. Precaution from Multi Threading
In the above code we saw how to lazy initialize instance variable. But here is a small problem. If two threads are trying to create the instance by calling the getInstance() method, it is possible that both check instance==null condition and get inside the if block.This will happen when one thread checks the null condition, got into the if block and is busy in initializing the instnace variable and has not yet initialized it. In the mean time second thread checks for instance==null and since the first thread has not yet instantiated the instance variable, the second thread enter the if block too. Both thread will end up creating 2 instances.
To avoid this, we need to synchronize the getInstance() method.
public synchronized static Singleton getInstance() { if(instance==null){ instance = new Singleton(); } return instance; }
This will create a lock on the Singleton class and only one thread can at a particular time enter the getInstance() method.
Another way would be to use synchronize block with lock on Singleton class.
public static Singleton getInstance() { synchronized (Singleton.class) { if(instance==null){ instance = new Singleton(); } }
To learn more about serialization refer blog Java Synchronization
4. Precaution while Serializing
How can we make sure that when a class is serialized and de-serialized only one instance gets created?
Lets first try to reproduce the problem. Below calss serializes the object in a file and then de-serializes it from the file.
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class TestSerialization { public static void main(String[] args) throws Exception{ //Get instance of Singleton Singleton singleton = Singleton.getInstance(); // Print the HashCode System.out.println(singleton); //Serialize the object in a file FileOutputStream fileOutputStream = new FileOutputStream(new File("sinleton.obj")); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(singleton); objectOutputStream.close(); //De-Serialize the same Sinleton object from the file FileInputStream fileInputStream = new FileInputStream(new File("sinleton.obj")); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Singleton s = (Singleton)objectInputStream.readObject(); objectInputStream.close(); //Print the HashCode of the de-serialized object System.out.println(s); } }Basically we have saved a object in a file and then retrieved the same object from the file.
The output is below
Singleton@1db9742 Singleton@1909752
Here the hash code printed is different for the serialized and deserialized object. So now we have to unique objects. This violates the Singleton pattern.
The solution here is to override the readResolve() method in the Singleton class. This informs the De-Serialization mechanism that same object instance should be returned.
public Object readResolve(){ return instance; }
If that was not enough, there is one more way to implement Singlton Class. Using Enums.
5. Singleton with enums
public enum SingletonEnum { instance; //Some instance variables on class SingletonEnum public int age; }The above code defines a enum with one instance variable. Thats it. You have your Singleton class.
Lets test it.
public class TestSingleton { public static void main(String[] args) { System.out.println(SingletonEnum.instance.hashCode()); System.out.println(SingletonEnum.instance.hashCode()); SingletonEnum.instance.age=8; System.out.println(SingletonEnum.instance.age); } }Output
31168322 31168322 8
Here both the problems of multi threading and serialization is solved. Also we can add one more instance to the enum so that instead of only one, now only two can be made. Also one of the questions that can be asked in interview.
For more Java Interview Questions click here