Digesting Singleton Design Pattern in Java
Design Patterns are very popular among software developers. A design pattern is a well described solution to a common software problem. The Singleton is one of the Creational Design Patterns in Java.
What is the purpose of Singleton?
The purpose of the singleton class is to control object creation, limiting the number of objects to only one. The singleton allows only one entry point to create the new instance of the class.
Since there is only one Singleton instance, any instance fields of a Singleton will occur only once per class, just like static fields. Singletons are often useful where we have to control the resources, such as database connections or sockets.
It seems to be a very simple design pattern but when it comes to implementation, it comes with a lot of implementation concerns. The implementation of Singleton pattern has always been a controversial topic among developers. Here, we are going to discuss how to create a Singleton class that fulfills its purpose :
Restrict the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine.
Let’s create Singleton class in java and test it in different conditions.
Create Singleton class in Java:
To implement the singleton class, the simplest way is to make the constructor of the class as private.
- Eager initialization:
In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a singleton class.
By making the constructor as private we are not allowing other class to create a new instance of the class we want to create the singleton. Instead, we are creating one public static method (commonly name as for getInstance()) to provide the single entry point to create the new instance of the class.
This approach has one drawback. Here instance is created even though client application might not be using it. This might be a considerable issue if your singleton class in creating a database connection or creating a socket. This may cause the memory leak problem. The solution is to create the new instance of the class, when needed. This can be achieved by Lazy Initialization method.
2. Lazy initialization:
Opposite to Eager initialization, here we are going to initialize new instance of the class in getInstance() method it self. This method will check if there is any instance of that class is already created? If yes, then our method (getInstance()) will return that old instance and if not then it creates a new instance of the singleton class in JVM and returns that instance. This approach is called as Lazy initialization.
We all know that in Java if the two objects are same then, their hash key have to be equal. Let’s test that. If the above singleton is correctly implemented than below code should return the same hash key.
Below is the output log with the hash code of both the instances.
We can see that both the instances are having the same hash code. So, that means above code will make the perfect singleton. Right???? No.
What about Java Reflection API?
In above singleton class, by using reflection we can create more than one instance. Those of you don’t know what is the Java Reflection API is, Java Reflection is a process of examining or modifying the run-time behavior of a class at run time.
We can make the new instance of the singleton class by changing the constructor visibility as public in run-time and create new instance using that constructor. Run the below code and see it our singleton survives?
Here is the output of hash codes of both instances.
Both the instances have a different hash code. That clearly indicates that our singleton class failed this test.
To prevent singleton failure while due to reflection we have to throw a run-time exception in constructor, if the constructor is already initialized and some class to initialize it again. Let’s update our SingletonClass.java.
Is our singleton class thread safe?
If two threads try to initialize our singleton class at almost the same time, what happens? Let’s test below code in which two threads are created almost simultaneously and they are calling getInstance().
If you run this code many times, you will see sometimes both the threads creates different instances.
That means our singleton class is not Thread safe. Both the threads calls out getInstance() method at the same time, the sSoleInstance == null condition will return for both the thread. So, two different instances of the same class will be created. That will break the singleton principle.
1. Make getInstance() synchronized:
Let’s make our getInstance() method synchronized.
As we made our getInstance() class synchronized the second thread will have to wait until the getInstance() method is completed for the first thread. This way we can achieve thread safety. But, there are some cons of using this approach:
- Slow performance because of locking overhead.
- Unnecessary synchronization that is not required once the instance variable is initialized.
2. Double check locking method:
We can overcome this issue if we use Double check locking method to create the singleton. In this, we make the singleton class in the synchronized block if the instance is null. So, the synchronized block will be executed only when the sSoleInstance is null and prevent unnecessary synchronization once the instance variable is initialized.
3. Use volatile keyword:
On the surface, this method looks perfect, as you only need to pay price for synchronized block one time, but it still was broken, until you make sSoleInstance variable volatile.
Without volatile modifier, it’s possible for another thread in Java to see half initialized state of _instance variable, but with volatile variable guaranteeing happens-before relationship, all the write will happen on volatile sSoleInstance before any read of sSoleInstance variable.
Now, our singleton class is thread safe. Making singleton thread safe is especially required in multi-threaded application environment like in Android Applications.
Make Singleton safe from Serialization:
Sometimes in distributed systems, we need to implement Serializable interface in Singleton class. By doing that we can store its state in the file system and retrieve it at later point of time. Let’s test our singleton class whether it maintains single instance after serializable and deserializable operations?
We can see that the hash code of both the instances are different. That is clearly violates singleton principle. The problem with above serialized singleton class is that whenever we deserialize it, it will create a new instance of the class.
To prevent creation of another instance we have to provide the implementation of readResolve() method. readResolve() replaces the object read from the stream. This ensures that nobody can create another instance by serializing and deserializing the singleton.
At end of the article, we can make our class a singleton class that is thread and reflection safe. This singleton is still not the perfect singleton. We can violate the singleton principle by creating more than one instance of the singleton class by using cloning or using multiple class loaders. But for the most of the applications, above implementation of singleton will work perfectly.