Singleton mode of design mode

Keywords: Java Design Pattern

There are eight single-case patterns

First: Hungry Han (static constant)

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Hungry Han Style (Static Constant)
class SingleTon1{
    //1. The constructor is private and cannot be new externally
    private  SingleTon1(){
        
    }
    //2. Create object instances within this class
    private final static SingleTon1 instance = new SingleTon1();
    //3. Provide a common static method to return an instance object
    public static  SingleTon1 getInstance(){
        return  instance;
    }
}

Advantages and disadvantages:

1.Advantage: This is a simple way to write, that is, instantiate the class when it is loaded, avoiding the problem of thread synchronization.

2.Disadvantages: Instantiation is done when the class is loaded, which does not have the effect of Lazy Loading. If this instance has not been used from beginning to end, it will result in a waste of memory

3. This classloder-based mechanism avoids the problem of multithreaded synchronization. However, instances are instantiated when classes are loaded, and most of them call the getInstance method in the singleton mode, but there are many reasons for class loading, so there is no other way to determine.(or any other static method) causes the class to load, and initializing instances does not have the effect of Lazy Loading

4. Conclusion: This single-case mode is available and may cause memory waste

Second: Hungry Han (static code block)

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Hungry Han Style (Static Code Block)
class SingleTon1{
    //1. The constructor is private and cannot be new externally
    private  SingleTon1(){

    }
    //2. Create object instances within this class
    private  static SingleTon1 instance;
    static {
        instance = new SingleTon1();
    }
    //3. Provide a common static method to return an instance object
    public static  SingleTon1 getInstance(){
        return  instance;
    }
}

Advantages and disadvantages:

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

2. Conclusion: This singleton mode is available, but may cause memory waste

Third: Lazy (thread insecure)

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Lazy (thread insecure)
class SingleTon1{
    //1. Create object instances inside this class
    private  static SingleTon1 instance;
    //2. The constructor is private and cannot be new externally
    private  SingleTon1(){

    }
    //3. Provide a static, common method for creating instance objects that are lazy when used
    public static  SingleTon1 getInstance(){
        if(instance == null){
            instance = new SingleTon1();
        }
        return  instance;
    }
}

Advantages and disadvantages:

1. Lazy Loading works, but can only be used under a single thread

2. If a thread enters an if(singleton == null) judgment statement block under multithreading, and has not yet had time to execute it down, and another thread passes the judgment statement, multiple instances will be generated. This is not possible in a multithreaded environment.

3. Conclusion: Do not use this mode in actual development

Fourth: Lazy (thread-safe, synchronization method)

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Lazy (thread-safe, synchronization method)
class SingleTon1{
    //1. Create object instances inside this class
    private  static SingleTon1 instance;
    //2. The constructor is private and cannot be new externally
    private  SingleTon1(){

    }
    //3. Provide a static, common method for addressing thread security issues by adding synchronized code
    public static synchronized SingleTon1 getInstance(){
        if(instance == null){
            instance = new SingleTon1();
        }
        return  instance;
    }
}

Advantages and disadvantages:

1. Solve thread insecurity

2. It is too inefficient for each thread to synchronize the getInstance() method when it wants to get an instance of a class. In fact, it is sufficient for this method to execute instantiation code only once. To get this kind of instance later, Return wakes up directly and the method is too inefficient to synchronize

3. Summary: In actual development, this is not recommended

Fifth: Lazy (synchronous code block) is not really thread safe

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Lazy (Thread Safe, Synchronize Code Blocks)
class SingleTon1{
    private  static SingleTon1 instance;
    private  SingleTon1(){

    }
    public static  SingleTon1 getInstance(){
        if(instance == null){
            synchronized (SingleTon1.class){
                instance = new SingleTon1();
            }
        }
        return  instance;
    }
}

Advantages and disadvantages:

1. This is intended to improve the fourth implementation because the previous synchronization method was too inefficient and resulted in instantiated blocks of code being synchronized

2. However, this synchronization does not work for thread synchronization. Consistent with the third implementation, adding a thread into the if(singleton==null) judgment block before it has time to go down and the other thread passes the judgment statement will result in multiple instances

3. Conclusion: This method cannot be used in actual development

Sixth kind: Double check

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//duplication check
class SingleTon1{
    private  static  volatile  SingleTon1 instance;
    private  SingleTon1(){

    }
    //Provides a static common method with double-checked code to solve thread security and lazy loading
    public static  SingleTon1 getInstance(){
        if(instance == null){
            synchronized (SingleTon1.class){
                if(instance == null){
                    instance = new SingleTon1();
                }
            }
        }
        return  instance;
    }
}

Advantages and disadvantages:

1. The Double-Check concept is commonly used in multi-threaded development. As shown in the code, we checked if(instance == null) twice to ensure thread safety.

2. This way, the instantiation code is executed only once, and when accessed again later, if(instance == null) is judged, the object is instantiated directly by Return, and method synchronization is avoided repeatedly

3. Thread security, delayed loading, high efficiency

4. Conclusion: This singleton design pattern is recommended for practical development.

Seventh: Static Internal Class

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        SingleTon1 instance = SingleTon1.getInstance();
        SingleTon1 instance2 = SingleTon1.getInstance();
        System.out.println(instance==instance2);//true
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}
//Static Internal Class
class SingleTon1{
    private  static  volatile  SingleTon1 instance;
    //Constructor Privatization
    private  SingleTon1(){

    }
    //Write a static internal class with a static property Singleton
    private static class SingletonInstance{
        private static final SingleTon1 INSTANCE = new SingleTon1();
    }
    //Provides a static common method that returns SingletonInstance.INSTANCE directly
    public static  SingleTon1 getInstance(){
        return  SingletonInstance.INSTANCE;
    }
    //Description 1. The static internal class SingletonInstance will not be loaded when the class is loaded by SingleTon1
    //2. When the getInstance method is called, the static internal class SingletonInstance performs class loading, which is thread-safe
}

Explanation of advantages and disadvantages:

1. This approach uses a class loading mechanism to ensure that there is only one thread initializing the instance

2. Static internal class methods are not instantiated immediately when the SingleTon1 class is loaded. Instead, when instantiation is required, call the getInstance method to load the SingletonInstance class to complete the instantiation of Singleton

3. Class static properties are only initialized when the class is first loaded, so here, the JVM helps us keep threads safe, and no other threads can enter when the class is initialized

4. Advantages: Avoid thread insecurity, use static internal class feature to achieve delayed loading, high efficiency

5. Conclusion: Introduction and use

Eighth: Enumeration

public class SingleTonTest01 {
    public static void main(String[] args) {
        //test
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
        instance.sayOK();
    }
}
//enumeration
enum Singleton{
    INSTANCE;//attribute
    public void sayOK(){
        System.out.println("ok~");
    }
}

Advantages and disadvantages:

1. This implements the singleton mode with the help of enumerations added in JDK1.5, which not only avoids multithreaded synchronization problems, but also prevents deserialization from re-creating new objects

2. This approach is advocated by Effeetive Java author Josh Bloch

3. Promotional Use

Posted by tilde on Fri, 24 Sep 2021 09:22:43 -0700