How to deal with Singleton along with Serialization

The best way to do this is to use the enum singleton pattern:

public enum MySingleton {
  INSTANCE;
}

This guarantees the singleton-ness of the object and provides serializability for you in such a way that you always get the same instance.

More generally, you can provide a readResolve() method like so:

protected Object readResolve() {
  return myInstance;
}

The solution with enum won't work with Singletons managed by Spring, EJB, Guice or any other DI framework. It works only with enums, only because enum is treated specially by the serialization algorithm.

Firstly, singletons don't need serialization, because if you deserialized it, and then deserialized singleton != YourSingleton.getInstance(), it would mean that you have two instances of your singleton, which means that YourSingleton isn't singleton at all, which may lead to unpredictable bugs.

However sometimes you need to serialize non-singleton which contains a reference to singleton. The solution is easy:

class NonSingleton implements Serializable {
    private transient YourSingleton singleton = YourSingleton.getInstance();
    ...
}

With Spring:

@Configurable
class NonSingleton implements Serializable {
    @Autowired
    private transient YourSingleton singleton;
    ...
}

Here below is my Singleton class that implements Serializable interface. Mark that it contains readResolve() method also.

import java.io.Serializable;

public class Singleton implements Serializable {

    private static Singleton singleton = new Singleton( );

    public int i = 1;

    private Singleton() { }

    public static Singleton getInstance( ) {

       return singleton;
    }

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

    public static void main(String[] args) {
        Singleton s1 = getInstance();
        System.out.println(s1.hashCode());

        Singleton s2 = getInstance();
        System.out.println(s2.hashCode());
    }
}

Below is the class that will first serialize and then deserialize the above class. Here deserialization takes place two times, but both time only one instance will be created because of readResolve() method.

public class SingletonSerializableDemo {

    static Singleton sing = Singleton.getInstance();
    static Singleton s1  = null;
    static Singleton s2 = null;
    public static void main(String[] args) {
        try {
             FileOutputStream fileOut =
             new FileOutputStream("E:/singleton.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(sing);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved");

             FileInputStream fileIn1 = new FileInputStream("E:/singleton.ser");
             FileInputStream fileIn2 = new FileInputStream("E:/singleton.ser");
             ObjectInputStream in1 = new ObjectInputStream(fileIn1);
             ObjectInputStream in2 = new ObjectInputStream(fileIn2);
             s1 = (Singleton) in1.readObject();
             s2 = (Singleton) in2.readObject();
             System.out.println(s1.hashCode() + " "+ s1.i);
             s1.i = 10;
             System.out.println(s2.hashCode() + " "+ s2.i);
             in1.close();
             in2.close();
             fileIn1.close();
             fileIn2.close();
          }catch(Exception i) {
             i.printStackTrace();
          }
    }
}

And the output will be:

Serialized data is saved
21061094 1
21061094 10

Conclusion: Singleton class can also be serialized by keeping readResolve() method in the Singleton class.


@ColinD is kind of right, but his answer also illustrates why singletons don't really jell with serialization.

Here's what happens when you serialize an enum value (see here).

The rules for serializing an enum instance differ from those for serializing an "ordinary" serializable object: the serialized form of an enum instance consists only of its enum constant name, along with information identifying its base enum type. Deserialization behavior differs as well--the class information is used to find the appropriate enum class, and the Enum.valueOf method is called with that class and the received constant name in order to obtain the enum constant to return.

So any additional state that you attach to your enum values does not survive serialization and deserialization.

You could do the same thing yourself, by adding custom serialization / deserialization code to your singleton classes. That code would need to either not record the singleton's state at all, or throw it away when the singleton is deserialized. Either way, you'd put the logic into a readResolve() method as explained by @ColinD's answer.

Now, I presume that the reason you want to serialize singletons is that you want to persist their state. Unfortunately, that presents a conceptual problem. Suppose that your application has instantiated the singleton in the normal course of events, and then it deserializes some object graph that includes a copy of a previous instance of the singleton. What can it do?

  • If it deserializes the singleton normally, it violates "singleton-ness".
  • If it doesn't then the application cannot access the singleton's previous state.

Tags:

Java

Singleton