views:

69

answers:

3

Consider I have a Singleton class defined as follows.

public class MySingleton implements Serializable{
 private static MySingleton myInstance;

 private MySingleton(){

 }
  static{
    myInstance =new MySingleton();
 }
 public static MySingleton getInstance(){
    return MySingleton.myInstance;
 }
}

The above definition according to me satisfies the requirements of a Singleton.The only additional behaviour added is that the class implements serializable interface.

If another class X get the instance of the single and writes it to a file and at a later point deserializes it to obtain another instance we would have two instances which is against the Singleton principle.

How can I avoid this or am I wrong in above definition itself.

+2  A: 

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;
}
ColinD
+3  A: 

@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.

However, 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.
Stephen C
All good points.
ColinD
A: 

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;
    ...
}
iirekm
Both solutions I mentioned will guarantee that a deserialized singleton == YourSingleton.getInstance(). And yes, of course it won't work with DI managed singletons, because those aren't what's being discussed here at all.
ColinD