1, Singleton mode - 6 implementations

Keywords: jvm

Design pattern

1, Singleton mode

characteristic:

  1. A singleton class can only have one instance

  2. A singleton class must create its own unique instance

  3. Singleton classes must provide this instance to all other objects

solve the problem:

  1. A global class is frequently created and destroyed

 

1. Lazy mode

public class SingletonOne {
    private SingletonOne() {}
    private static SingletonOne instance = null;
    public static SingletonOne getInstance() {
        // Thread safety exists here
        if (instance == null) {    
            instance = new SingletonOne();
        }
        return instance;
    }
}

 

2. Starving Han model

public class Singleton2 {
    private Singleton2() {}
    private static Singleton2 instance = new Singleton2();  // Class loading is slow
    public static Singleton2 getInstance() {
        return Singleton2.instance;
    }
}

 

3. Dual check mode (DCL)

public class Singleton3 {
    private Singleton3() {}
    private static Singleton3 instance = null;
    public static Singleton3 getInstance() {
        if (null == instance) {
            // JVM Thread safety caused by instruction rearrangement of compiler
            synchronized (Singleton3.class) {
                if (instance== null) {
                    instance= new Singleton3();
                }
            }
        }
        return instance;
    }
}

 

4. Double check mode - optimized version

public class Singleton4 {
    private Singleton4() {}
    // volatile Keyword disallows reordering of instructions
    private volatile static Singleton4 instance = null;
    public static Singleton4 getInstance() {
        if (null == instance) {
            synchronized (Singleton4.class) {
                if (instance== null) {
                    instance= new Singleton4();
                }
            }
        }
        return instance;
    }
}

 

5. Static internal class

/**
 * 1.The static inner class LazyHolder cannot be accessed from outside, only when the Singleton.getInstance Method to get the INSTANCE object INSTANCE.
 * 2.INSTANCE The time of object initialization is not when Singleton is loaded, but when getInstance method is called to load the static inner class LazyHolder.
 *   So this way is to use the loading mechanism of classloader to achieve lazy loading and ensure the thread safety of building a single instance.
 */
public class Singleton5 {
    private Singleton5() {}
    private static class LazyHolder {
        private static final Singleton5 INSTANCE = new Singleton5();
    }
    public static Singleton5 getInstance() {
        return LazyHolder.INSTANCE;
    }
}

5.1 reflection breaks the constraint of singleton mode

//Get constructor
Constructor con = Singleton5.class.getDeclaredConstructor();
//Set to accessible
con.setAccessible(true);
//Construct two different objects
Singleton5 singleton1 = (Singleton5)con.newInstance();
Singleton5 singleton2 = (Singleton5)con.newInstance();
//Verify different objects
System.out.println(singleton1);
System.out.println(singleton2);
​
// result
singleton.Singleton5@4554617c
singleton.Singleton5@74a14482

 

6. Enumeration

// Prevent using reflection to forcibly build singleton objects
public enum Singleton6 {
    INSTANCE;
    public void doSomething(){
    }
}

 

7. Summary

realization Thread safety Lazy load Prevent reflection build
Lazy mode no yes no
Starved Han model yes no no
Double check mode yes yes no
Static inner class yes yes no
enumeration yes no yes

Note: generally, the 1st and 2nd lazy way is not recommended, and the 4th hungry way is recommended. The fifth static inner class approach is only used if you want to explicitly implement the lazy loading effect. If deserialization is involved in creating objects, try the sixth enumeration.

 

8. Supplement

  1. Volatile keyword can not only prevent instruction rearrangement, but also ensure that the variable value accessed by thread is the latest value in main memory. I will explain the detailed principle of volatile in the future comics.

  1. The singleton pattern implemented by enumeration can not only prevent the singleton object from being constructed by reflection, but also ensure that the return result of the deserialization is the same object when the enumeration class object is deserialized.

  1. For the singleton pattern implemented by other methods, if you want to be both serializable and deserialized to the same object, you must implement the readResolve method.

Posted by FourthChapter on Wed, 24 Jun 2020 20:54:18 -0700