Singleton pattern - breaking Singleton

Breaking Singleton

Breaking Singleton using Reflection

import java.lang.reflect.Constructor;

public class TestDriver {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = null;
        try {
            Constructor[] constructors = Singleton.class.getDeclaredConstructors();
            for (Constructor constructor: constructors) {
                constructor.setAccessible(true);
                singleton2 = (Singleton) constructor.newInstance();
                break;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("instance1.hashCode(): " + singleton1.hashCode());
        System.out.println("instance2.hashCode(): " + singleton2.hashCode());

        // Output
        // instance1.hashCode(): 1159190947
        // instance2.hashCode(): 804564176
    }
}

Enum Singleton

To overcome this situation with Reflection, we can use the Enum to implement Singleton design pattern. Java ensures any enum value is instantiated only once in a Java program.

public enum EnumSingleton {

    INSTANCE;

    public static void work() {
        //do something
    }
}

Breaking Singleton using Serialization

In certain case, you may be forced to implement Serializable interface in Singleton class, especially in the distributed systems. Whenever we de-serialize a class, it creates a new instance of the class. This can be challenging, especially with Singleton pattern.

import java.io.Serializable;

public class SingletonWithSerialized implements Serializable {

    private static final long serialVersionUID = 1L;

    private SingletonWithSerialized() {}

    private static SingletonWithSerialized instance = new SingletonWithSerialized();

    public static SingletonWithSerialized getInstance() {
        return SingletonWithSerialized.instance;
    }
}

You can prevent this by implementing the readResolve() method.

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

Links to this note