4

I have some questions about implementing the Singleton Pattern in Java.

  1. There is a chance of having multiple instances of a Singleton when we use cloning. Is there a specific way we can prevent it?

  2. What will be the impact if we are creating another instance of a singleton using serialization & deserialization?

mort
  • 12,988
  • 14
  • 52
  • 97
Madhuri
  • 126
  • 9
  • If other instances could be created, this is not singleton. If you need to clone or serialize *state* of singleton, use special object that reflects its *state* and perform clone/serialization on it, not singleton itself. – Alex Salauyou May 07 '15 at 12:46
  • 1
    No, that's the whole idea. Write the singleton so those can't happen. But think about not writing Singletons. Google prohibits them: https://code.google.com/p/google-singleton-detector/ – duffymo May 07 '15 at 12:47

5 Answers5

2

1) Do not make Singleton Cloneable and nobody will make a clone of it

2) If Singleton is Serialiazable and it does not use readResolve to prevent duplicates you will get duplicates while deserializing it and it will not be a Singleton anymore. Impact depends on the application logic

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
1

Effective Java Item 3: Elvis is your class.

public class Elvis {
  private static final Elvis INSTANCE = new Elvis();
  private Elvis() { ... }
  public static Elvis getInstance() { return INSTANCE; }
  public void leaveTheBuilding() { ... }
}

If you want to serialize it:

// readResolve method to preserve singleton property
private Object readResolve() {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
   return INSTANCE;
}

Or you could use enum:

 // Enum singleton - the preferred approach
 public enum Elvis {
   INSTANCE;
   public void leaveTheBuilding() { ... }
}
Chris
  • 98
  • 5
0

I'm not sure about your second point, but this answers the first one:

public class SingletonObject {

    /**
     * The one and only instance of this class
     */
    private static SingletonObject ref;

    /**
     * Creates the object. Must not be called more than once.
     */
    private SingletonObject() {
        // no code required
    }

    /**
     * Returns a reference to the singleton object
     * @returns The singleton object
     */
    public static synchronized SingletonObject getSingletonObject() {
        if (ref == null) {
            // First call, so create it
            ref = new SingletonObject();
        }
        return ref;
    }

    /**
     * Prevents cloning of the object.
     * @throws CloneNotSupportedException If method is called
     */
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException(); 
    }
}

You can simply override the cloning method. Note that getSingletonObject is synchronized, which prevents to instances of the object to be created if ref equals null and two threads call the function at the same time.

Hexaholic
  • 3,299
  • 7
  • 30
  • 39
0

To add to @Evgeniy Dorofeev comment, I do not see any reason to make it cloneable and expecting it to be a singleton as well. For whatever reason if it implements Cloneable you can always throw an exception by overriding clone() method.

jags
  • 176
  • 5
0
  1. There is a chance of having multiple instances of Singleton when we use cloning. Is there a specific way we can prevent it?

Don't implement Cloneable interface. You will automatically get CloneNotSupportedExceptionwhen you try to call `clone()~ on it.

  1. What will be the impact If we are creating another instance of singleton using Serialization & De-serialization?

Yes, you can create multiple versions of your singleton class using Serialization. to prevent this don't implement Serializable interface or if you want to explicitly prevent serialization, you could override writeObject() to throw Exception during Serialization.

Code :

   // Double check Singleton   
class Singleton implements Serializable {

    private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        throw new IOException("Serialization is not allowed");
    }

    private static final long serialVersionUID = -6022571167467223517L;

    private volatile static Singleton singletonInstance = null;

    private Singleton() {

    }

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

            }
        }
        return singletonInstance;
    }

}
TheLostMind
  • 35,966
  • 12
  • 68
  • 104