Common methods of singleton pattern and objects created by reflection serialization violence

1. Single case mode

Single instance mode, as the name implies, has only one instance, and she is responsible for creating her own objects. This class provides a way to access its unique objects, which can be accessed directly without instantiating the objects of this class. Let's take a look at the implementation methods.

1.1 lazy mode

Instances are created only when they are used, "relatively lazy". Only when they are used, do you check whether there are instances. If there are instances, return them and create new ones.

Disadvantage: 2 objects will appear when multi-threaded access (thread is not safe)

/**
 * TODO(Description)
 *  Lazy mode
 * @author vioelt
 * @Title LazySingleton
 * @Description:
 * @date 2020/6/28 8:51
 */
public class LazySingleton {
    private  static LazySingleton instance;
    public LazySingleton() {
    }
    public  static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
1.2 lazy double check lock * * (thread safety)**

Although thread safety is ensured, resources are consumed

/**
 * TODO(Description)
 *  Lazy double check lock
 * @author vioelt
 * @Title LockLazySingleton
 * @Description:
 * @date 2020/6/28 8:51
 */
public class LockLazySingleton {
    //Use volatile to prevent reordering due to new LockLazySingleton() non atomic operation
    private volatile static LockLazySingleton instance;

    public LockLazySingleton() {
    }
    
    public  static LockLazySingleton getInstance() {
        if (instance == null) {
            //Prevent multithreading, realize code block control and reduce resource waste
            synchronized (LockLazySingleton.class) {
                if (instance == null) {
                    instance = new LockLazySingleton();
                }
            }
        }
        return instance;
    }
}
1.3 starvation mode (static constant)

Class loading is slow, but the speed of getting object is fast, and multi threading problem is avoided, but the object will not be released until the end of the program. And the object is stored in the global, which is decorated with static

/**
 * TODO(Description)
 *  Starvation mode (static constant)
 * @author vioelt
 * @Title HuangrySingleton
 * @Description:
 * @date 2020/6/28 8:51
 */
public class HuangrySingleton {
     
     private static HuangrySingleton instance = new HuangrySingleton();  
     private HuangrySingleton(){
     }
     public static HuangrySingleton getInstance() {  
     return instance;  
     }  
 }
1.4 starvation mode (static code block)

The only difference is that the new method is used to create objects directly. Here, static is used to execute the methods in static when the class is loaded to create objects. The writing method is different

/**
 * TODO(Description)
 *  Starved Han model
 * @author vioelt
 * @Title HuangryStaticSingleton
 * @Description:
 * @date 2020/6/28 9:00
 */
public class HuangryStaticSingleton {
    private static HuangryStaticSingleton instance;

    static {
        instance = new HuangryStaticSingleton();
    }

    private HuangryStaticSingleton() {}

    public static HuangryStaticSingleton getInstance() {
        return instance;
    }
}
1.5 static internal class

Similar to the loading mode of starved man mode, class loading is used to ensure that there is only one object when initializing an instance, while static internal class initialization is used to ensure that it can only be completed when necessary

Initialization of an instance of InnerSingleton.

Compared with the above four methods, the delay loading efficiency is higher and the thread insecurity is avoided

 * TODO(describe)
 *  Static inner class
 * @author vioelt
 * @Title InnerSingleton
 * @Description:
 * @date 2020/6/28 9:00
 */
public class InnerSingleton {
    private InnerSingleton() {}

    private static class SingletonInstance {
        private static final InnerSingleton INSTANCE = new InnerSingleton();
    }

    public static InnerSingleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

Although static internal classes crush the above four methods, which are applicable to most scenes, private construction methods can only prevent (and all need to privatize the construction methods to prevent others from directly creating objects through new methods), can not directly create objects through new methods, and can't prevent reflection attacks,

2. Reflection cracking (static internal class example)

/**
 * TODO(Description)
 *  Reflection cracking
 * @author zzx
 * @Title Test
 * @Description:
 * @date 2020/6/28 8:51
 */
public class Test {
    public static void main(String[] args) throws Exception {
        InnerSingleton instance = InnerSingleton.getInstance();
        // Get all constructors, including non public ones
        Constructor<InnerSingleton> constructor = InnerSingleton.class.getDeclaredConstructor();
        //Violent access to private methods
        constructor.setAccessible(true);
        //Created through the newInstance() method, the restricted generated object of this method can only call the parameterless constructor
        InnerSingleton innerSingleton = constructor.newInstance();
        System.out.println(instance);
        System.out.println(innerSingleton);
        System.out.println(instance==innerSingleton);
    }
}

**Results:**
*

3. Serialize the operands to see if the objects are the same

/**
 * TODO(Description)
 *  Serialize operation object
 * @author zzx
 * @Title Test
 * @Description:
 * @date 2020/6/28 8:51
 */
public class Test {
    public static void main(String[] args) throws Exception {
        InnerSingleton s = InnerSingleton.getInstance();
   //ObjectOutputStream object output stream, writing InnerSingleton test.text File, note that InnerSingleton needs to implement Serializable, otherwise it will report an error, so as to realize serialization and storage
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(new File("test.text")));
        //Write objects to
        oos.writeObject(s);
        oos.close();
        //Then write out the object
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("test.text"));
        InnerSingleton innerSingleton=(InnerSingleton) ois.readObject();
        ois.close();
        System.out.println(s);
        System.out.println(innerSingleton);
        System.out.println(innerSingleton==s);
    }
}

4. Powerful enumeration singleton mode

Reflection security, serialization / deserialization security, simple writing

/**
 * TODO(Description)
 *  Enumeration singleton
 * @author zzx
 * @Title SingletonEnum
 * @Description:
 * @date 2020/6/28 10:46
 */
public class SingletonEnum {
    public enum SingleDemoEnum {
        INSTANCE;
        public  void method() {
            // do work.
        }
    }
}

Posted on Sat, 27 Jun 2020 23:21:02 -0400 by veryconscious