StackTips

Singleton Design Pattern in Java

Singleton design pattern belongs to the creational family of patterns that governs the instantiation process. This pattern ensures at most one instance of a particular class is ever created in your application. Following are some of the real-time examples listed below.
  • Project Configuration: Class that reads your project configuration can be made Singleton. By making this singleton, you are allowing global access for all classes in your application. If the project configs are stored in a file, it just reads once and holds on application cache. You don’t have to read the file multiple times.
  • Application Log: Logger will be used everywhere in your application. It must be initialized once and used everywhere.
  • Analytics and Reporting: If you are using some kind of data analysis tool like Google Analytics, you will notice that they are designed to be a singleton. It initializes once and being used everywhere for each user action.

Singleton Class Diagram
Singleton Class Diagram

In the above class diagram, the Singleton class has a private static instance variable named “instance”. The default constructor of “Singleton” class is made private, to prevent other class to instantiate it. Static getInstance() method, will be accessible globally which returns the singleton class object.

1. Implementing Sington Class

  • Make the default constructor private. Private constructor prevents the direct instantiation of the object from other classes.
  • Create a public static getInstance() method. A member declared as static can be accessed without creating an object using the new operator. This method returns the instance of the singleton class.
  • Lazy initialization is preferable to create an object on first use.

Example:  

Creating a singleton class using lazy initialization

Singleton.java

package com.stacktips.creational.singleton;

class Singleton {
	private static Singleton instance;

	//Private Constructor prevents any other class from instantiating
	private Singleton() {
	}

	public static Singleton getInstance() {
		
		//Lazy initialization, creating object on first use
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
	
	public void display() {
		System.out.println("Hurray! I am display from Singleton!");
	}
}

SingletonTest.java

package com.stacktips.creational.singleton;

public class SingletonTest {
	public static void main(String args[]) {
		
		//Compilation error not allowed
		//Singleton object = new Singleton();

		Singleton object = Singleton.getInstance();
		object.display();
		
		//Your app logic goes here
		System.out.println("Singleton object obtained");
	}
}

In the above example, we have created a Singleton instance using lazy initialization. The getInstance() method is instantiating the class for the first use.

2. Singleton and Thread Safety

Thread-safe code is particularly important in Singleton. Two instances of Singleton class will be created if the getInstance() called simultaneously by two threads. To avoid such issues, we’ll make the getInstance() method synchronized. This way we force every thread to wait until its turn before it executes. I.e. no two threads can be entered into getInstance() method at the same time.

public static synchronized Singleton getInstance() {
		
		// Lazy initialization, creating object on first use
		if (instance == null) {
			instance = new Singleton();
		}
		return instance;
}

The above implementation will answer to thread safety problem, however, synchronized methods are expensive and will have a serious performance hit. We will change the getInstance() method not to check for synchronization, if the instance is already created.

public static synchronized Singleton getInstance() {

		// Lazy initialization, creating object on first use
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}

	return instance;

}

3. Singleton and Early Initialization

Using early initialization we will initialize upfront before your class is being loaded. This way you don’t need to check for synchronization as it is initialized before being used ever.

package com.stacktips.creational.singleton;

class Singleton implements Cloneable {
	private static Singleton instance;

	// Private Constructor prevents any other class from instantiating
	private Singleton() {
	}

	public static synchronized Singleton getInstance() {

		// Lazy initialization, creating object on first use
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}

		return instance;
	}

	// Prevent cloning
	@Override
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}

	public void display() {
		System.out.println("Hurray! I am display from Singleton!");
	}
}

4. Singleton and Object Cloning

Java has the ability to create a copy of the object with similar attributes and state form original object. This concept in java is called cloning. To implement cloning, we have to implement java.lang.Cloneable interface and override clone() method from Object class. It is a good idea to prevent cloning in a singleton class. To prevent cloning on singleton object, let us explicitly throw CloneNotSupportedException exception in clone() method.

package com.stacktips.creational.singleton;

import java.io.Serializable;

class Singleton implements Cloneable, Serializable {

	private static Singleton instance;
	
	private int value;

	// Private Constructor prevents any other class from instantiating
	private Singleton() {
	}

	public static synchronized Singleton getInstance() {

		// Lazy initialization, creating object on first use
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}

		return instance;
	}

	// Restrict cloning of object
	@Override
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}

	public void display() {
		System.out.println("Hurray! I am display from Singleton!");
	}
	
	public int getValue() {
		return value;
	}
	
	public void setValue(int value) {
		this.value = value;
	}
}

5. Singleton and Serialization

Java Serialization allows to convert the state of an object into a stream of bytes so that it can easily be stored or transferred. Once the object is serialized, you can deserialize it, back to  object from the byte stream. If a singleton class is meant to be serialized, it will end up creating duplicate objects. Let us have a look into the example below, explaining the problem,

Singleton.java

package com.stacktips.creational.singleton;

import java.io.Serializable;

class Singleton implements Cloneable, Serializable {

	private static Singleton instance;
	
	private int value;

	// Private Constructor prevents any other class from instantiating
	private Singleton() {
	}

	public static synchronized Singleton getInstance() {

		// Lazy initialization, creating object on first use
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}

		return instance;
	}

	// Restrict cloning of object
	@Override
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}

	public void display() {
		System.out.println("Hurray! I am display from Singleton!");
	}
	
	public int getValue() {
		return value;
	}
	
	public void setValue(int value) {
		this.value = value;
	}
}

SerializationTest.java

package com.stacktips.creational.singleton;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

public class SerializationTest {
	
	public static void main(String[] args) {
		
		//getting singleton instance
		Singleton instanceOne = Singleton.getInstance();
		instanceOne.setValue(10);
		
		try {
                   // Serialize to a file
		   ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.txt"));
                   out.writeObject(instanceOne);
                   out.close();
                   instanceOne.setValue(20);
            
            // Serialize to a file
            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.txt"));
            Singleton instanceTwo = (Singleton) in.readObject();
            in.close();
 
            System.out.println("Instance One Value= " + instanceOne.getValue());
            System.out.println("Instance Two Value= " + instanceTwo.getValue());
 
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
  }
}

In the above example, the Singleton class is implementing the serializable interface, which means the state of its object can be persisted. SerializableTest is the test class, used to test Singleton class. Inside main() method we are persisting the state of Singleton instance into a file and retrieve it later. Now compile and run the program, you will notice that the state of both instances (instanceOne and instanceTwo) are different, which means that they are two different objects.  Here we are violating the rules of singleton by allowing it to create two different objects of same class.

To solve this issue, we need to include readResolve() method in our DemoSingleton class. This method will be invoked before the object is deserialized. Inside this method, we will call getInstance() method to ensure a single instance of Singleton class is exist application wide.

Singleton.java

package com.stacktips.creational.singleton;

import java.io.Serializable;

class Singleton implements Cloneable, Serializable{

	private static final long serialVersionUID = 1L;
	private static Singleton instance;
	private int value;

	// Private Constructor prevents any other class from instantiating
	private Singleton() {
	}

	public static synchronized Singleton getInstance() {

		// Lazy initialization, creating object on first use
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
		}

		return instance;
	}

	protected Object readResolve() {
        return getInstance();
    }
	
	// Restrict cloning of object
	@Override
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}

	public void display() {
		System.out.println("Hurray! I am display from Singleton!");
	}
	
	public int getValue() {
		return value;
	}
	
	public void setValue(int value) {
		this.value = value;
	}
}

Serializable is a marker interface. A marker interface contains no fields or method declaration. Serializable interface is used as a marker to specify that the class can be serialized.

writeObject() and readObject() methods are called while the object is serialized or deserialized. writeObject() method is used to write the state of the object for its particular class so that its corresponding readObject() method can read it.

readObject() method is responsible for reading the object from the stream and to restore the class fields.

6. Did you know?

  • Singleton classes are used sparingly. Do not think of this pattern, unless you know what you are doing. As the object is created in the global scope, this is riskier in resource-constrained platforms
  • Beware of object cloning. Double check and block object’s clone method
  • Careful when multiple threads accessing the singleton class
  • Careful of multiple class loaders they can break your singleton
  • Implement strict type if your singleton class is serialized