Q-1). How one will guarantee the thread-safety issue while implementing the Singleton Design Pattern?

A-1). Multiple threads will create multiple instances, which violates the core principle of the Singleton Design Pattern. To avoid this scenario, one has to use synchronized keyword, the double-checking principle, or Bill Pugh Solution.

Q-2). How to overcome the serialization issues while implementing the Singleton Design Pattern?

A-2). Serialization creates a new instance of Deserialization. To avoid this problem, we have to implement the readResolve() method.

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

Q-3). How to overcome the reflection issues while implementing the Singleton Design Pattern?

A-3). Reflection is a very strong mechanism. With the help of reflection, one can access all the properties present within a class. By using Reflection API, one can break the Singleton pattern. To overcome this we have to throw an exception if an instance already exists.

if (instance != null) {
    throw new RuntimeException("Use getInstance() method to create instance");
}

Q-4). Can you please elaborate on handling the reflection issues while implementing the Singleton Design Pattern?

A-4). Let’s analyze some code snippets, which will clear the idea of handling reflection while implementing the Singleton Design Pattern.

public class ReflectionSingleton {
    private static ReflectionSingleton instance;

    private ReflectionSingleton() {}

    public static ReflectionSingleton getInstance() {
        if (instance == null) {
            instance = new ReflectionSingleton();
        }
        return instance;
    }
}

In the above code snippet, one can notice that I just declared the constructor as private of the class named ReflectionSingleton.java. And I haven’t handled the reflection-safe logic. Now let’s define the creation of the object part.

public class ReflectionTestMasterclassApplication {
    private static final Logger LOG = LoggerFactory.getLogger(ReflectionTestMasterclassApplication.class);
    public static void main(String[] args) throws Exception {
        ReflectionSingleton instance1 = ReflectionSingleton.getInstance();

        // Using Reflection to create another instance
        Constructor<ReflectionSingleton> constructor = ReflectionSingleton.class.getDeclaredConstructor();
        constructor.setAccessible(true); // Breaks private access
        ReflectionSingleton instance2 = constructor.newInstance();

        LOG.info("Instance 1: {}", instance1.hashCode());
        LOG.info("Instance 2: {}", instance2.hashCode()); // Shouldn't happen in proper Singleton
    }
}

Now, I haven’t handled the reflection-safe logic in the constructor of the ReflectionSingleton class. The 2 LOG statements above will create 2 instances of Singleton and you can see the hashCode value of both the objects are different. That means it violates the Singleton Design Pattern core principle.

INFO com.springcavaj.designpattern.singleton.ReflectionTestMasterclassApplication - Instance 1: 2047329716

INFO com.springcavaj.designpattern.singleton.ReflectionTestMasterclassApplication - Instance 2: 96639997

Let’s handle the reflection-safe mechanism while implementing the Singleton Design Pattern.

public class ReflectionSafeSingleton {
	
	private static ReflectionSafeSingleton instance;
	private ReflectionSafeSingleton() {
		if(null != instance) {
			throw new RuntimeException("Use getInstance() method to create instance");
		}
	}

	public static ReflectionSafeSingleton getInstance() {
		if(null == instance) {
			instance = new ReflectionSafeSingleton();
		}
		return instance;
	}
}

Now in this case I have handled the reflection-safe logic that if the instance is not null then throw an exception. In the ReflectionTestMasterclassApplication.java I have written the code to create the object by using the reflection mechanism, and it throws the RuntimeException.

ReflectionSafeSingleton instance3 = ReflectionSafeSingleton.getInstance();
		
		// Using Reflection to create another instance
        Constructor<ReflectionSafeSingleton> constructorSafe = ReflectionSafeSingleton.class.getDeclaredConstructor();
        constructorSafe.setAccessible(true); // Breaks private access
        ReflectionSafeSingleton instance4 = constructorSafe.newInstance();
        
        LOG.info("Instance 1: {}", instance3.hashCode());
        LOG.info("Instance 2: {}", instance4.hashCode()); // Shouldn't happen in proper Singleton
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.springcavaj.designpattern.singleton.ReflectionTestMasterclassApplication.main(ReflectionTestMasterclassApplication.java:39)
Caused by: java.lang.RuntimeException: Use getInstance() method to create instance
	at com.springcavaj.designpattern.singleton.design.ReflectionSafeSingleton.<init>(ReflectionSafeSingleton.java:16)
How does it work?
  1. Normal Object Creation – If the instance is null, the constructor allows the first object creation.
  2. Reflection attack – if reflection is used to create another instance, the constructor checks if null != instance and throws an exception.

Q-5). How to overcome the cloning issues while implementing the Singleton Design Pattern?

A-5). Cloning is the process of creating an instance, and it can create new instances which again violates the core principle of the Singleton Design Pattern. To overcome this problem, one has to overwrite the clone() method to throw an exception.

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