Stop Breaking Singleton Pattern in Java

Salitha Chathuranga
4 min readJul 2, 2022

--

Let’s learn how to create a full safe Singleton class

What is Singleton?

This is the most common design pattern asked in many places…This should be known by any developer! So, I’m not going to deeply explain what it is since that is not the focus of this article.

Singleton means we do not allow to re create objects and only maintain only one instance of a class per JVM…

How do we create a Singleton class?

There are few steps to create such class..Let me list down!

  1. Private static Singleton class type member ☑️
  2. Private constructor ☑️
  3. Public static method to return the instance ☑️

Singleton Variations

There are few variations in Singleton pattern actually. Let me brief about them if you cannot recall… 😎

  • Eager Initialization => Create instance at class loading time
  • Lazy Initialization => Create object when it was asked first
  • Static Block Implementation => Create instance at class loading time — difference from eager is: we can throw any exception using the block
  • Synchronized Singleton — method level => Partially Thread safe: whole getInstance() method is synchronized
  • Synchronized Singleton — class level => Partially Thread safe: synchronization is on the class inside synchronized block
  • Synchronized Singleton — with double checking => Thread safe in almost all scenarios

Let’s imagine we have created a Singleton class including thread safety also…

public class Singleton {
private static Singleton instance = null;

private Singleton() {
}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

Do you think it is fully safe??? 😬 No guys! It’s still vulnerable!!! Let’s discuss the issues still it has…

There are 3️⃣ main scenarios that breaksSingleton even though we make it Thread Safe❗️They are:

  1. Cloning
  2. Deserialization
  3. Reflection

I’m going to discuss about them and how to overcome the issues making a full safe Singleton! 😍

✅ Cloning

If we need to create a clone of any object, we must implement the class from Cloneable interface. Otherwise it will be throwing CloneNotSupportedException.

Code => Singleton.getInstance().clone()Result =>
Exception in thread "main" java.lang.CloneNotSupportedException: singleton.Singleton
at java.lang.Object.clone(Native Method)
at singleton.Singleton.main(Singleton.java:22)

So it’s implicitly stopping cloning. Actually cloning is not relatable since this is about Singleton! So don’t implement from Cloneable interface!

✅ Deserialization

Serialization refers to converting an object into byte stream. The deserialization is the opposite of that — converting a byte stream back to object. Usually in Java, we use ObjectInputStream and ObjectOutputStream classes to achieve this.

If our Singleton is perfectly fine, after performing read and write both, we should get the same hash code if we have only 1 object..Right? Let’s try out..

import java.io.*;

public class SingletonMain {
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
Singleton instanceOne = Singleton.getInstance();
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(instanceOne);
out.close();

ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
Singleton instanceTwo = (Singleton) in.readObject();
in.close();

System.out.println("Hashcode of Object 1: " + instanceOne.hashCode());
System.out.println("Hashcode of Object 2: " + instanceTwo.hashCode());
}
}

What did you get? Again 2️⃣ hash codes…Breaks Singleton! 😕

Solution: Override readResolve() — method coming from ObjectInputStream class.

class Singleton implements Serializable {

private static Singleton instance = null;

private Singleton() {
if (instance != null) {
throw new RuntimeException("You have broken Singleton class!");
}
}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

public Object readResolve() {
return instance;
}


}

Check again now! You will get the same hashcode which means we have only 1 object exactly.

✅ Reflection

Java provides a set of APIs to get details like class metadata through Reflection APIs…We have bunch of methods to examine the classes and create instances and etc…

Let’s try to create Singleton object using reflections.

public class SingletonMain {
public static void main(String[] args) throws CloneNotSupportedException {
Singleton instanceOne = Singleton.getInstance();
Singleton instanceTwo = null;
try {
Constructor constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
instanceTwo = (Singleton) constructor.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Hashcode of Object 1: " + instanceOne.hashCode());
System.out.println("Hashcode of Object 2: " + instanceTwo.hashCode());
}
}

What did you get? Again 2️⃣ hash codes…Breaks Singleton! 😕

Solution: Check the object exists(not NULL) inside the constructor itself and throw a Runtime Exception if it’s existing.

Required changes are highlighted in the code snippet…

class Singleton {

private static Singleton instance = null;

private Singleton() {
if (instance != null) {
throw new RuntimeException("You have broken Singleton class!");
}

}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

}

Check again now! You will get the same hashcode which means we have only 1 object exactly.

💪💪💪💪💪

Final version of our Singleton will be like this now! 😎

class Singleton implements Serializable {

private static Singleton instance = null;

private Singleton() {
if (instance != null) {
throw new RuntimeException("You have broken Singleton class!");
}

}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

public Object readResolve() {
return instance;
}


}

OR

class Singleton implements Serializable {

private static Singleton instance = null;

private Singleton() {
if (instance != null) {
throw new RuntimeException("You have broken Singleton class!");
}

}

public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}

public Object readResolve() {
return instance;
}


}

This is all about making Singleton fully safe guys!!! Now it’s behaving like a PRO 😎. Apply these resolution techniques to fix your Singleton classes…It will solve some problems before hand.

Bye guys! Keep reading!!!

--

--

Salitha Chathuranga
Salitha Chathuranga

Written by Salitha Chathuranga

Associate Technical Lead at Sysco LABS | Senior Java Developer | Blogger

Responses (9)