03_ Single case design mode

Posted by pod2oo5 on Tue, 25 Jan 2022 10:31:09 +0100

1 Introduction to single example design mode

Class singleton design pattern is to take certain methods to ensure that there can only be one object instance for a class in the whole software system, and the class only provides a method to obtain the object instance (static method).

2. There are eight ways of single case design mode

2.1 hungry Han formula (static constant)

/**
 * static const 
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private final static Singleton singleton = new Singleton();
    public static Singleton getInstance() {
        return singleton;
    }
}

This method is relatively simple, that is, the instantiation is completed when the class is loaded, so as to avoid the problem of thread synchronization. However, the instantiation is completed when the class is loaded, which does not achieve the effect of Lazy Loading. If this instance is never used from beginning to end, it will cause a waste of memory.

2.2 hungry Chinese (static code block)

/**
 * Static code block
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static Singleton singleton;
    static {
        singleton = new Singleton();
    }
    public static Singleton getInstance() {
        return singleton;
    }
}

This method is actually similar to the above method, except that the class instantiation process is placed in the static code block, and the code in the static code block is executed when the class is loaded to initialize the class instance. The advantages and disadvantages are the same as above.

2.3 lazy (thread unsafe)

/**
 * Static code block
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static Singleton singleton;
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

It has the effect of Lazy Loading, but it can only be used under single thread. If a thread enters the if (singleton == null) judgment statement block and has not had time to execute it, and another thread also passes the judgment statement, multiple instances will be generated. Therefore, this method cannot be used in a multithreaded environment.

2.4 lazy (thread safety synchronization method)

/**
 * synchronized
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static Singleton singleton;
    //Provide a static public method, add synchronous processing code, and solve thread safety problems
    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

The thread safety problem is solved, and the efficiency is too low. When each thread wants to obtain an instance of a class, it must synchronize the getInstance() method. In fact, this method only executes the instantiation code once. If you want to obtain this class instance, you can directly return it. Method is too inefficient to synchronize.

2.5 lazy (thread safe - synchronous code block)

/**
 * synchronized
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static Singleton singleton;
    //Provide a static public method, add synchronous processing code, and solve thread safety problems
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

2.6 double check DCL

/**
 * DCL
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static volatile Singleton singleton;
    //Provide a static public method, add synchronous processing code, and solve thread safety problems
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

The concept of double check is often used in multithreading development. As shown in the code, we have conducted two if (singleton == null) checks to ensure thread safety. The instantiation code is executed only once. When accessing again later, judge if (singleton == null) to return the instantiated object directly, and avoid repeated method synchronization. Thread safety; Delayed loading; High efficiency.

2.7 static internal class

/**
 * Static inner class
 */
class Singleton {
    // Privatize the constructor. new object instances cannot be used externally
    private Singleton(){}
    private static class SingletonInstance {
        private static final Singleton singleton = new Singleton();
    }
    private static synchronized Singleton getInstance() {
        return SingletonInstance.singleton;
    }
}

This method adopts the mechanism of class loading to ensure that there is only one thread when initializing the instance. The static internal class SingletonInstance will not be instantiated immediately when the Singleton class is loaded. When instantiation is required, the SingletonInstance class will be loaded by calling the getInstance method, so as to complete the instantiation of Singleton.

The static properties of the class will only be initialized when the class is loaded for the first time, so the JVM helps us ensure the safety of threads. When the class is initialized, other threads cannot enter.

2.8 enumeration

public class SingletonTest {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
    }
}
/**
 * Enumeration class
 */
enum Singleton {
    INSTANCE;
}

This is done with the help of jdk1 5 to implement the singleton mode. It can not only avoid the problem of multi-threaded synchronization, but also prevent deserialization and re creation of new objects.

Topics: Java Design Pattern Singleton pattern