SINGLETON PATTERN

Sometimes it’s important for some classes to have exactly one instance. There are many objects we only need one instance of them and if we, instantiate more than one, we’ll run into all sorts of problems like incorrect program behavior, overuse of resources, or inconsistent results.

There are only two points in the definition of a singleton design pattern,

  • There should be only one instance allowed for a class
  • We should allow global point of access to that single instance.

From the definition, 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 Java Singleton pattern has always been a controversial topic among developers. Here we will learn about Singleton design pattern principles, different ways to implement Singleton design pattern and some of the best practices for its usage. Lazy initialization will be beneficial when we want to delay the initialization until it is not needed. because if we use eager initialization and if initialization fails there is no chance to get the instance further while in lazy initialization we may get it in second chance. In Lazy initialization we will not get instance until we call getInstance () method while in eager initialization it creates instance at the time of class loading.

Below are some examples where Singleton pattern violation situation can be found.

We will compare the hash code values of the objects to verify the similar objects. If hash code values of two objects are equal, those objects must be equal.

1. Reflection

Using reflection we can set the private constructor to become accessible at runtime as shown in the example below.

package com.myjavablog.singleton;

import java.lang.reflect.Constructor;

public class SingletonReflection {

private static SingletonReflection instance = new SingletonReflection();

private static SingletonReflection getInstance() {
return instance;
}

private SingletonReflection(){
System.out.println("Creating Object.......");
}

public static void print(String name, SingletonReflection obj){
System.out.println("Object Name : "+ name +" Hashcode: "+ obj.hashCode());
}

public static void main(String[] args) throws Exception {

SingletonReflection sr1 = SingletonReflection.getInstance();
SingletonReflection sr2 = SingletonReflection.getInstance();

print("S1", sr1);
print("S2", sr2);

Class clazz = Class.forName("com.myjavablog.singleton.SingletonReflection");
Constructor<SingletonReflection> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonReflection sr3 = constructor.newInstance();

print("S3", sr3);

}
}

Output:

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Creating Object.......
Object Name : S3 Hashcode: 1735600054

Fix for above problem:

Throw Runtime Exception if someone tries to make instance in case one instance already exists. This code will go into the private constructor of the Singleton class.

private SingletonReflection(){

if(instance!= null)
throw new RuntimeException("Can't create an object . Use getIntance method to create the objects ");

System.out.println("Creating Object.......");
}

Output post fix:

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.myjavablog.singleton.SingletonReflection.main(SingletonReflection.java:37)
Caused by: java.lang.RuntimeException: Can't create an object . Use getIntance method to create the objects
at com.myjavablog.singleton.SingletonReflection.<init>(SingletonReflection.java:17)
... 5 more

 

2.Cloning:

If we try to make instance by cloning it, the generated hash code of cloned copy doesn’t match with the actual object so it also violates the Singleton principle.

package com.myjavablog.singleton;

import java.lang.reflect.Constructor;

public class SingletonCloning implements Cloneable{

private static SingletonCloning instance = new SingletonCloning();

private static SingletonCloning getInstance() {

return instance;
}

private SingletonCloning() {

System.out.println("Creating Object.......");
}

@Override
protected Object clone() throws CloneNotSupportedException {
//if(instance!= null)
// throw new CloneNotSupportedException("Cant clone singleton objects");

return super.clone();
}

public static void print(String name, SingletonCloning obj){
System.out.println("Object Name : "+ name +" Hashcode: "+ obj.hashCode());
}

public static void main(String[] args) throws Exception {

SingletonCloning sr1 = SingletonCloning.getInstance();
SingletonCloning sr2 = SingletonCloning.getInstance();

print("S1", sr1);
print("S2", sr2);

SingletonCloning sr3 = (SingletonCloning) sr2.clone();

print("S3", sr3);

}
}

Output:

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Object Name : S3 Hashcode: 1735600054

Fix for above issue: Throw CloneNotSupportedException from the clone () method if someone tries to make other instance of it. Uncomment the commented line from clone () method.

@Override
protected Object clone() throws CloneNotSupportedException {
if(instance!= null)
throw new CloneNotSupportedException("Cant clone singleton objects");

return super.clone();
}

Post fix Ouput :

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Exception in thread "main" java.lang.CloneNotSupportedException: Cant clone singleton objects
at com.myjavablog.singleton.SingletonCloning.clone(SingletonCloning.java:22)
at com.myjavablog.singleton.SingletonCloning.main(SingletonCloning.java:39)

 

3. Serialization/Deserialization:

When we serialize an object and deserialize it again there are different hash code values generated as shown in the example below. So our Singleton principle breaks in case of object serialization/deserialization.

 

package com.myjavablog.singleton;

import java.io.*;

public class SingletonSerialize implements Serializable {

private static SingletonSerialize instance = new SingletonSerialize();

private static SingletonSerialize getInstance() {

return instance;
}

private SingletonSerialize() {

System.out.println("Creating Object.......");
}

public static void print(String name, SingletonSerialize obj){
System.out.println("Object Name : "+ name +" Hashcode: "+ obj.hashCode());
}

public static void main(String[] args) throws Exception {

SingletonSerialize sr1 = SingletonSerialize.getInstance();
SingletonSerialize sr2 = SingletonSerialize.getInstance();

print("S1", sr1);
print("S2", sr2);

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\anupb\\IdeaProjects\\DesignPatterns\\tmp\\s2.ser"));
oos.writeObject(sr2);

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\anupb\\IdeaProjects\\DesignPatterns\\tmp\\s2.ser"));
SingletonSerialize sr3 = (SingletonSerialize) ois.readObject();

print("S3", sr3);

}
}

Output:

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Object Name : S3 Hashcode: 2074407503

 

Fix for above issue: Implement readResolve () method in the Singleton class as shown below

private Object readResolve(){

System.out.println("Applying read Resolve .......");
return instance;
}

Post fix output:

Creating Object.......
Object Name : S1 Hashcode: 356573597
Object Name : S2 Hashcode: 356573597
Applying read Resolve .......
Object Name : S3 Hashcode: 356573597

 

4. Multithreaded:

Singleton will work properly in multithreaded environment only if eager instantiation has been done because in this case instance creation will happen at the time of class loading only. But for Lazy instantiation we will have to take care of multiple things. If we want to delay the instantiation because of cost, we use to go with lazy. Following code demonstrates the behavior of Singleton instance when two threads are getting executed by comparing their hash code values. Be careful while running the following code as it will work only in Java 8 and later versions.

package com.myjavablog.singleton;

import java.io.Serializable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingletonThread implements Serializable {

//Lazy initialization
private static SingletonThread instance = null;

private static SingletonThread getInstance() {

if(instance == null)
instance = new SingletonThread();

return instance;
}

private SingletonThread() {

System.out.println("Creating Object.......");
}

public static void print(String name, SingletonThread obj){
System.out.println("Object Name : "+ name +" Hashcode: "+ obj.hashCode());
}

static void useSingleton(){
SingletonThread singletonThread = SingletonThread.getInstance();
print("singletonThread", singletonThread);
}

public static void main(String[] args) throws Exception {

ExecutorService service = Executors.newFixedThreadPool(2);

service.submit(SingletonThread::useSingleton);
service.submit(SingletonThread::useSingleton);
service.shutdown();
}
}

Output:

Creating Object.......
Object Name : singletonThread Hashcode: 722702912
Object Name : singletonThread Hashcode: 722702912

 

Creating Object.......
Creating Object.......
Object Name : singletonThread Hashcode: 1588147852
Object Name : singletonThread Hashcode: 1059951119

When you run the above program many times you will notice that in multithreaded environment sometimes Singleton principle works but sometimes it violates. Therefore we need to synchronize the getInstance () method as shown below –

private static synchronized SingletonThread getInstance() {

if(instance == null)
instance = new SingletonThread();

return instance;
}

After applying synchronize keyword in the getInstance () method the program will execute properly without any issue but in Java instead of synchronizing whole method we can synchronize only the block of code which is affected while creating instance to escape the extra overhead as below –

private static SingletonThread getInstance() {

if(instance == null) { // Check 1
synchronized (SingletonThread.class) {
if(instance == null) {// Check 2
instance = new SingletonThread();
}
}
}
return instance;
}

From the above code we have narrowed down the scope of synchronization for performance reasons. Notice that if a thread at line # 3 sees that instance is null and then it gets the lock of object at line # 5. At the same time if another thread already has the lock it will create the instance. So to make sure no other thread has already acquired the lock we will apply one more check after acquiring the lock as shown below. This method is called Double Checked Locking.

 

Sometimes double checked locking also breaks the Principle of Singleton. Java runtime publishes half initialized variable. Suppose 2 threads thread1 & thread2 are entering into the code it goes through the line #3 to line #6 and created the instance. At the same time thread 2 enters and it knows that there is something in variable named as ‘instance’ (since it is at half initialized state) and it returns the same from line #10. Therefore Singleton principle breaks.

To address this situation use volatile keyword at the time of instance declaration. Value of volatile variable will be published only when the change completes. Change to write operation happens before read operation in volatile variable. In short all threads will see the same value of variable.

private static SingletonThread instance = null;

 

5. Enum Singleton:

Joshua Bloch suggests the use of Enum to implement Singleton design pattern as Java ensures that any enum value is instantiated only once in a Java program. Since Java Enum values are globally accessible, so is the singleton. The drawback is that the enum type is somewhat inflexible; for example, it does not allow lazy initialization.

package com.myjavablog.singleton;

public enum SingletonEnum {

private static SingletonEnum instance = null;

private static void doSomething() {

//do Something
}

}

Enum Singleton doesn’t violate principle of Singleton in any case described above.

 

 

Some Real time Examples of Singleton Design Pattern –

 

  1. Logger – You use Singleton pattern for the Logger class. In case it is not Singleton, every client will have its own Logger object and there will be concurrent access on the Logger instance in Multithreaded environment, and multiple clients will create/write to the Log file concurrently, this leads to data corruption.
  2. Loading Configuration file in Web Application
  3. Consider the situation of AudioDriverService which is designed in Singleton Pattern. So we are allowed to create just a single instance of AudioDriverService class. Now actually your Windows Media Player or Youtube Player both will share the same object of AudioDriverService rather than creating a new instance.
  4. Database connections

6 thoughts on “SINGLETON PATTERN”

  1. Hello,
    Nice article..I have few doubts
    1) Can you replace Singleton with Static Class in Java?
    2) Why don’t we create evey object with singleton pattern it will reduce memory leak?

    Reply
    • Good questions Nisha –
      1) Can you replace Singleton with Static Class in Java?
      You can’t due to below differences in them –

      – Static class will have all its members as static only unlike Singleton.
      – It can be lazily loaded whereas static will be initialized whenever it is first loaded.
      – Singleton object stores in Heap but, static object stores in stack.
      – We can clone the object of Singleton but, we can not clone the static class object.
      – Singleton can use the Object Oriented feature of polymorphism but static class cannot.

      2) Why don’t we create every object with singleton pattern it will reduce memory leak?

      It is recommended that whenever you want to perform unique/common operation across your application then you can go for Singleton. Consider below examples –

    • -Logger – You use Singleton pattern for the Logger class. In case it is not Singleton, every client will have its own Logger object and there will be concurrent access on the Logger instance in Multithreaded environment, and multiple clients will create/write to the Log file concurrently, this leads to data corruption.
    • -Loading Configuration file in Web Application
    • -Consider the situation of AudioDriverService which is designed in Singleton Pattern. So we are allowed to create just a single instance of AudioDriverService class. Now actually your Windows Media Player or Youtube Player both will share the same object of AudioDriverService rather than creating a new instance.
    • -Database connections
    • You dont have this situation all the time. Your object attributes are always changing at runtime in real time. So you can’t go for Singleton every time except you have particular situation like i mentioned in above examples.

      Reply
    • Would like to add one more point for the first question.
      Static class and singleton instance both have their own advantages depending on the scenarios.
      For example look at the below scenarios –
      1. If one wants to define a bunch of util function then prefer the static class to define it. It is a more optimized way as its functions are bonded at the compile time
      2. If one wants to handle resources as well with functions then prefer singleton instance. It provides better control over handling resources and its states.

      Reply
  2. To add one more point for the first question –
    It depends on the situation to situation, Static class and Singleton has their own advantages.
    1. When one wants to implement a bunch of util functions, prefer static classes as static methods are bonded at compile time. It gives better performance.
    2. If one wants to handle resources with functions prefer singleton instance. It gives better control over it.

    Reply

Leave a Comment

Bitnami