How to deal with Singleton along with Serialization

后端 未结 9 1590
感情败类
感情败类 2020-12-04 13:06

Consider I have a Singleton class defined as follows.

public class MySingleton implements Serializable{
 private static MySingleton myInstance;

 private MyS         


        
相关标签:
9条回答
  • 2020-12-04 13:56

    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.

    0 讨论(0)
  • 2020-12-04 14:03

    Singleton classes is just like a manager or controller and in general we do not want to save the state of any controller instead of the entity. Generally we need to save the object state of any entity not the controller.
    Singleton is singleton for a single class loader not for multiple class loader. If a class is loaded in a classes loader then the other class loader will not know about it so it behaves like this.

    0 讨论(0)
  • 2020-12-04 14:07

    Let say we have the following singleton class:

    public class ConnectionFactory implements Serializable {
        private static ConnectionFactory INSTANCE;
    
        private ConnectionFactory() {  }
    
        public static ConnectionFactory getInstance() {
            if (INSTANCE == null) {
                synchronized(ConnectionFactory.class) {
                    if(INSTANCE == null)
                        INSTANCE = new ConnectionFactory();
                }
            }
            return INSTANCE;
        }
    }
    

    Now we have the main class like below for serialising and deserializing objects:

     public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
         ConnectionFactory INSTANCE=ConnectionFactory.getInstance();
         ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("connFactory.ser"));  
         oos.writeObject(INSTANCE);  
         oos.close();
    
         // Here I am recreating the instance by reading the serialized object data store
         ObjectInputStream ois = new ObjectInputStream(new FileInputStream("connFactory.ser"));  
         ConnectionFactory factory1 = (ConnectionFactory) ois.readObject();  
         ois.close();  
    
         // I am recreating the instance AGAIN by reading the serialized object data store
         ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream("connFactory.ser"));  
         ConnectionFactory factory2 = (ConnectionFactory) ois2.readObject();  
         ois2.close();
    
         // Let's see how we have broken the singleton behavior
         System.out.println("Instance reference check->" +factory1.getInstance());
         System.out.println("Instance reference check->" +factory2.getInstance());
         System.out.println("=========================================================");
         System.out.println("Object reference check->" + factory1);
         System.out.println("Object reference check->" + factory2);
    }
    

    So if we execute above code we will get following behaviour: "it has created two objects and one static reference for INSTANCE. That means if we read the serialized format of a singleton object multiple times, we will create multiple objects. This is not what a singleton object is supposed to do. So can we avoid i?, Yes, we can."

    To avoid multiple instances of singleton class we will use following method provided by serialization:

    private Object readResolve() throws ObjectStreamException {
        return INSTANCE;
    }
    

    This will prevent the creation of multiple instances of a singleton class.

    0 讨论(0)
提交回复
热议问题