Design Pattern

Breaking Singleton in Java and How to Prevent It

1. Reflection

Reflection: Reflection API can be used to change the access level of the constructor from private to public, and then instantiate the class as many times as desired.

Breaking Singleton

import java.lang.reflect.Constructor;

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

// Breaking Singleton using Reflection
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton instanceOne = constructor.newInstance();
Singleton instanceTwo = constructor.newInstance();

In the above code, instanceOne and instanceTwo are different instances of the Singleton class, breaking the Singleton pattern.

To prevent breaking singleton through reflection, throw a run-time exception in the constructor if it detects more than one instance creation.

Preventing Singleton Break

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
        if (instance != null) {
            throw new RuntimeException("Use getInstance() method to get the single instance of this class.");
        }
    }

    public static Singleton getInstance() {
        return instance;
    }
}

In the above code, if the constructor is already initialized and we try to initialize it again, it throws a runtime exception.

2. Serialization

Serialization: If you serialize an object of a singleton class and then deserialize that object, it will create a new instance, breaking the singleton pattern.

Breaking Singleton

import java.io.*;

public class Singleton implements Serializable {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

// Breaking Singleton using Serialization
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(Singleton.getInstance());
out.close();

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

In the above code, Singleton.getInstance() and instanceTwo are different instances of the Singleton class, breaking the Singleton pattern.

Preventing Singleton Break

To prevent breaking singleton through serialization, implement readResolve() method in the class and return the same Singleton instance.

public class Singleton implements Serializable {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    protected Object readResolve() {
        return getInstance();
    }
}

In the above code, the readResolve() method ensures that the same instance of the class is returned when deserializing.

3. Cloning

Breaking Singleton

If the class implements the Cloneable interface, then the singleton property can be broken by creating a clone of the singleton instance.

public class Singleton implements Cloneable {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

// Breaking Singleton using Cloning
Singleton instanceOne = Singleton.getInstance();
Singleton instanceTwo = (Singleton) instanceOne.clone();

In the above code, instanceOne and instanceTwo are different instances of the Singleton class, breaking the Singleton pattern.

Preventing Singleton Break

To prevent breaking singleton through cloning, override clone() method and throw an exception.

public class Singleton implements Cloneable {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
}

In the above code, we override the clone() method and throw a CloneNotSupportedException. This ensures that the clone method is not allowed on the Singleton class.

4. Multiple Class Loaders

Breaking Singleton

If multiple class loaders load the singleton class, each class loader will have its own instance of the singleton class. This is a complex issue and generally occurs in environments where there are multiple class loaders, like in web servers.

Preventing Singleton Break

One solution could be to use a parent class loader to load the Singleton class. This way, the class is loaded by a single class loader and the Singleton property is maintained.

5. Double-Checked Locking Issue

Breaking Singleton

In some environments, the “Double-Checked Locking” can be broken. This happens when the assignment to the singleton instance is performed before the constructor for the singleton is called.

Preventing Singleton Break

Use an “Initialization-on-demand holder idiom”, which is a secure way of lazy initialization singleton object.

public class Singleton {
    private Singleton() {}

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

In the above code, the Singleton instance is created only when the getInstance() method is called for the first time. This ensures that the Singleton property is maintained even in multi-threaded environments.

Remember, these methods are generally not recommended as they violate the design principles of the Singleton pattern. It’s important to be aware of these potential issues when implementing a Singleton in your code.

I hope these examples help you understand how to break and prevent breaking of Singleton in Java. Happy coding! 😊

Avatar

Neelabh

About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.

You may also like

Blog Design Pattern

Understanding the Builder Design Pattern in Java | Creational Design Patterns | CodeTechSummit

Overview The Builder design pattern is a creational pattern used to construct a complex object step by step. It separates
Blog Design Pattern Spring Boot

Mastering Dependency Injection and Inversion of Control: A Comprehensive Guide

Inversion of Control (IoC) is a design principle in which the control flow of a program is inverted: instead of the