Singleton modes are hungry and slacker, but slacker here.

Three classic implementations of Java singletons

1, the enumeration

public enum EnumSingleton {
    INSTANCE;
    public void talk(a) {
        System.out.println("This is an EnumSingleton " + this.hashCode()); }}Copy the code

Each member variable in an enumeration is an instance of each enumeration itself. Each enumeration inherits from the java.lang.Enum class. Each member of an enumeration is public static final by default.

Summary: Enumeration is the simplest and safest way to implement singletons. We’ll talk about that later

Static inner class

public class StaticInnerClass {
    // Private constructor
    private StaticInnerClass(a) {}// Get the instance
    public static StaticInnerClass instance(a){
        // Hanky-hank initializes
        return InnerClass.instance;
    }
    Static inner classes are thread-safe when initially loaded by the JVM
    private static class InnerClass{
        // Initialize member variables when the inner class is loaded
        private static StaticInnerClass instance = newStaticInnerClass(); }}Copy the code

The class loading order is attached

3. Double check lock (DCL)

/* Three features of concurrent programming: atomicity, visibility, and orderliness */
public class DCL {
    private DCL(a) {}// Volatile ensures visibility and order
    private static volatile DCL instance = null;
    public static DCL getInstance(a){
        if(instance ! =null) return instance;
        //synchronized guarantees atomicity
        synchronized (DCL.class){
            if (instance == null) {
                /* New DCL() resolves in the JVM as 1, creates instance to create space in the heap 2, initializes attributes 3, assigns the memory address of the object to instance. The second and third steps are not necessarily related, and the order may be reverse. You may write code that executes in an inconsistent order, causing instructions to be reordered
                /* The effect of volatile visibility (with multiple CPUS) visibility is due to memory and CPU interaction issues resolved by the MESI protocol regarding subsequent updates to the MESI protocol */
                instance = newDCL(); }}returninstance; }}Copy the code

Destroy the singleton

1. Reflex attacks

		// Get the private constructor of the singleton class by reflection
		Constructor constructor = DCL.class.getDeclaredConstructor();
		// Set brute force for private members
		constructor.setAccessible(true);
		// Create multiple different instances of a singleton class by reflection
		DCL s1 = (DCL) constructor.newInstance();
		// Create multiple different instances of a singleton class by reflection
		DCL s2 = (DCL) constructor.newInstance();
		s1.tellEveryone();
		s2.tellEveryone();
		System.out.println(s1 == s2);
Copy the code

2. Serialization attacks

		// The object serializes the stream to operate on the object
		ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("file"));
		// Get an object from the singleton
		DCL s1 = DCL.getSingletonInstance();
		// Serialize a singleton to a file through a serialized stream
		outputStream.writeObject(s1);
		// By serializing the stream, the serialized object information in the file is read into memory
		ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(new File("file")));
		// Create an object by serializing the stream
		DCL s2 = (DCL) inputStream.readObject();
		s1.tellEveryone();
		s2.tellEveryone();
		System.out.println(s1 == s2);
Copy the code

Conclusion: The above two attacks are not valid for enumerations. Enumerations cannot get objects through reflection, and enumerations cannot serialize objects