Detailed Explanation of Java Singleton Pattern

  • 2021-12-09 09:00:49
  • OfStack

Catalog Hungry Lazy Lazy (locked synchronized) Lazy (partially locked synchronized) Lazy (DCL) Lazy (DCL) Final Edition Static Internal Class Summary

Hungry Han style


/**
 *  Hungry Han style 
 *  Class is loaded into memory, it is instantiated 1 A singleton, JVM Ensure thread safety 
 *  Simple use: Recommended 
 *  Only 1 Disadvantages: The class is instantiated when it loads, whether it is used or not 
 */
public class Demo01 {
	// Begin to create a new one 1 Objects 
    private static final Demo01 INSTANCE = new Demo01();
	// Structure 
    private Demo01(){};
	// Call  getInstance  Returns when the  INSTANCE , only 1 Objects created 
    public static Demo01 getInstance(){
        return INSTANCE;
    }
    public static void main(String[] args) {
        Demo01 m1 = Demo01.getInstance();
        Demo01 m2 = Demo01.getInstance();
        // The result is true
        System.out.println(m1 == m2);
    }
}

 Singleton Mode (Hungry Type) Advantages: Hungry Type is a typical space for time. When the class is loaded, it will create a class instance. Whether you use it or not, it will be created first, and then every time you call it, you don't need to judge again, saving running time. 
 Disadvantages: Whether it is used or not, the class will be instantiated when it is loaded, which will be wasted 1 Fixed memory space 
 Improvement: Let the object be created when it is used. ------>   Lazy type 

Lazy type


/**
 *  Lazy type 
 *  Class is loaded into memory, it is instantiated 1 A singleton, JVM Ensure that threads are unsafe 
 *  Only 1 Disadvantages: Although it achieves the purpose of on-demand, it brings thread insecurity 
 */
public class Demo02 {
    private static Demo02 INSTANCE ;
    private Demo02(){};
    public static Demo02 getInstance(){
        // Judge  INSTANCE  Whether it is empty or not 
       if(INSTANCE == null){
           try{
               Thread.sleep(1);
           }catch (InterruptedException e){
               e.printStackTrace();
           }
           INSTANCE = new Demo02();
       }
       return INSTANCE;
    }
    public static void main(String[] args) {
        for(int i = 0 ; i < 100 ; i++){
            new Thread(()->
            // Outputting the object's hashcode Value, judging whether it is only by whether the contrast ratio is equal 1 Object of 
                    System.out.println(Demo02.getInstance().hashCode())
            ).start();
        }
    }
}

 Singleton mode (lazy type) Advantages: Lazy type is a typical time for space, that is, every time you get an instance, you will judge to see if you need to create an instance, wasting the time of judgment. Of course, if 1 If no one uses it, no instance will be created, which saves memory space. 
 Disadvantages: Lazy style may have multiple different objects when accessed by multiple threads. 
 Improvement method: to create method getInstance Lock     ------>    Lazy type (locked synchronized ) 

Lazy type (locked synchronized)


/**
 *  Lazy type ( Lock )
 *  Class is loaded into memory, it is instantiated 1 A singleton, a lock on the method that created the object, JVM Ensure thread safety 
 *  Only 1 Disadvantages: Although locking can ensure that the thread is safe, it will slow down the whole method. 
 */
public class Demo03 {
    private static Demo03 INSTANCE ;
    private Demo03(){};
    // Method locking 
    public static synchronized Demo03 getInstance(){
        // Business logic 
        // Judge  INSTANCE  Whether it is empty or not 
       if(INSTANCE == null){
           try{
               Thread.sleep(1);
           }catch (InterruptedException e){
               e.printStackTrace();
           }
           INSTANCE = new Demo03();
       }
       return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i = 0 ; i < 100 ; i++){
            new Thread(()->
                    System.out.println(Demo03.getInstance().hashCode())
            ).start();
        }
    }
}

 Singleton Mode (Lazy Lock) Advantages: Lazy Lock can ensure the safety of threads, but when the locking method getInstance When there is business logic code in, it will slow down the whole object creation process. 
 Disadvantages: Lock the whole method, which reduces the running time of the method 
 Improved method: Lock the program block of creating method, and do not lock the business logic code part   --------> Lazy type (partially locked synchronized ) 

Lazy type (partially locked synchronized)


/**
 *  Lazy type ( Partial locking )
 *  Class is loaded into memory, it is instantiated 1 A singleton, lock the part of the method that created the object, and reduce the time 
 */
public class Demo04 {
    private static Demo04 INSTANCE ;
    private Demo04(){};
    // Method locking 
    public static Demo04 getInstance(){
        // Business logic 
        // Judge  INSTANCE  Whether it is empty or not 
       if(INSTANCE == null){
           // Lock part of the code block of the method 
           synchronized (Demo04.class){
               try{
                   Thread.sleep(1);
               }catch (InterruptedException e){
                   e.printStackTrace();
               }
               INSTANCE = new Demo04();
           }
       }
       return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i = 0 ; i < 100 ; i++){
            new Thread(()->
                    System.out.println(Demo04.getInstance().hashCode())
            ).start();
        }
    }
}

 Singleton mode (partial locking lazy type) Advantages: Speeds up the running of the program, and only locks the part where the object is created 
 Disadvantages: Pass if After judgment, there will be multiple threads waiting for thread resources, etc. 1 After the execution of threads is completed, the first 2 Three threads to create objects. 
 Improvement method: add two layers if Judgment can prevent this problem from happening  --------> Double-layer inspection lock 

Lazy Style (DCL)


/**
 *  Lazy type (DCL)
 * Double Check Lock
 */
public class Demo04 {
    private static Demo04 INSTANCE ;
    private Demo04(){};
    // Method locking 
    public static Demo04 getInstance(){
        // Business logic 
        // Judge  INSTANCE  Whether it is empty or not 
       if(INSTANCE == null){
           // Lock part of the code block of the method 
           synchronized (Demo04.class){
               // Judge and check again  INSTANCE  Whether it is empty or not 
               if(INSTANCE == null){
                   try{
                       Thread.sleep(1);
                   }catch (InterruptedException e){
                       e.printStackTrace();
                   }
               }
               INSTANCE = new Demo04();
           }
       }
       return INSTANCE;
    }
    public void m(){
        System.out.println("m");
    }
    public static void main(String[] args) {
        for(int i = 0 ; i < 100 ; i++){
            new Thread(()->
                    System.out.println(Demo04.getInstance().hashCode())
            ).start();
        }
    }
}

 Singleton mode (lazy type DCL ) Advantages: Speeds up object creation time while ensuring thread security. 
 Disadvantages: When an object is rearranged by instructions, the 2 Although threads get the object, it is an incomplete object, which is prone to problems 
 Improved method: add to this method volatile Keyword can prevent instruction rearrangement problems. 

Extension 1: Why use two layers of if to judge?

Answer: Because using two layers of if can improve the running speed of the method, because if judgment consumes less time, but synchronized consumes a lot of time. Adding a layer of if to the outside can help filter out many thread accesses.

Lazy Style (DCL) Final Edition


 Singleton Mode (Hungry Type) Advantages: Hungry Type is a typical space for time. When the class is loaded, it will create a class instance. Whether you use it or not, it will be created first, and then every time you call it, you don't need to judge again, saving running time. 
 Disadvantages: Whether it is used or not, the class will be instantiated when it is loaded, which will be wasted 1 Fixed memory space 
 Improvement: Let the object be created when it is used. ------>   Lazy type 
0

Locking INSTANCE can prevent instruction rearrangement and ensure the integrity of objects.

Extension: Why should volatile be added to DCL mode?

Answer: We should consider the java object creation process and CPU out-of-order execution.

The java object creation process can be divided into:


 Singleton Mode (Hungry Type) Advantages: Hungry Type is a typical space for time. When the class is loaded, it will create a class instance. Whether you use it or not, it will be created first, and then every time you call it, you don't need to judge again, saving running time. 
 Disadvantages: Whether it is used or not, the class will be instantiated when it is loaded, which will be wasted 1 Fixed memory space 
 Improvement: Let the object be created when it is used. ------>   Lazy type 
1

When instruction rearrangement occurs, the order becomes


 Singleton Mode (Hungry Type) Advantages: Hungry Type is a typical space for time. When the class is loaded, it will create a class instance. Whether you use it or not, it will be created first, and then every time you call it, you don't need to judge again, saving running time. 
 Disadvantages: Whether it is used or not, the class will be instantiated when it is loaded, which will be wasted 1 Fixed memory space 
 Improvement: Let the object be created when it is used. ------>   Lazy type 
2

When the first thread accesses, instruction rearrangement occurs, the object has just been created for 1.5 years, and the internal value of the object has not been initialized and assigned. At this point, the second thread accesses, and what he reads is the object created to 1.5 and initialized to empty. Eventually, the object will be incomplete.

Static inner class

When loading the external class, the internal class will not be loaded. Only when the getInstance method is called for the first time, JVM loads Singleton04Holder and initializes INSTANCE. Only one thread can obtain the initialization lock of the object, while other threads cannot initialize it, thus ensuring the uniqueness of the object.


public class Demo04 {
    private Demo04 () {
    }
    private static class Demo04Holder {
        private final static Demo04 INSTANCE = new Demo04 ();
    }
    public static Demo04 getInstance() {
        return Demo04Holder.INSTANCE;
    }
    public static void main(String[] args) {
        for(int i=0; i<100; i++) {
            new Thread(()->{
                System.out.println(Demo04.getInstance().hashCode());
            }).start();
        }
    }
}

Summarize

This article is here, I hope to give you help, but also hope that you can pay more attention to this site more content!


Related articles: