当前位置:网站首页>Defects in singleton mode of DCL and other implementations of singleton

Defects in singleton mode of DCL and other implementations of singleton

2020-11-09 16:59:00 Meng Xin J

  DCL:Double Check Lock , Double check lock . In singleton mode, you can use DCL To ensure the efficiency of program execution .

 1 public class SingletonDemo {
 2     private static SingletonDemo singletonDemo = null;
 3     private SingletonDemo(){
 4     }
 5 
 6     public SingletonDemo getSingletonDemo(){
 7         if(singletonDemo == null){
 8             synchronized (SingletonDemo.class){
 9                 if(singletonDemo == null){
10                     singletonDemo = new SingletonDemo();
11                 }
12             }
13         }
14         return singletonDemo;
15     }
16 }

It's traditional DCL An implementation of the singleton pattern , The first non null judgment is to avoid instance properties having been instantiated and assigned , The following thread still enters synchronized  Decorated code block , To lock 、 Unlock , It leads to inefficiency ; The second non null judgment is to avoid instance properties having been assigned , Wait for the thread in the queue to repeat object creation and assignment . and DCL It can ensure that only one object initialization will be carried out under multithreading . But there are still flaws in this code .

 

defects

Instruction set

   Let's write a separate object creation method , Take a look at the instruction set for this operation

public void aa(){
        singletonDemo = new SingletonDemo();
    }

    First compile the class , And then use idea  Of jclasslib The plug-in looks at this class , The instruction set is as follows :

  

  The instructions are new 、dup、invokespecial、putstatic, Last return return , here dup It's a copy operation , That is to make a copy of the element at the top of the stack , You can ignore it here . So the key instructions are three ,1、new( Instantiation , Declare objects , Allocation address ),2、invokespecial( initialization , Call constructor , Assign properties ),3、putstatic( Assign this object to a property singletonDemo).

 

Command rearrangement

   There is instruction rearrangement in single thread , What is command rearrangement , For example, code x=1; y=1; x++; y++; y=x+y; JVM When loading, you may first load to  y, Then it won't wait x load , Go straight to the execution y++  , In this way, the operation efficiency is improved , This sort of code order is instruction rearrangement . But at the same time, instruction rearrangement is not random rearrangement , It's going to be data dependent , For example, although loading first y, Yes y++ , Also loaded x, But it's not going to go on y=x+y; Because it's operated on the right y  In front of y++ Changed the value , So there's something about y++ Data dependency ,JVM It's not going to allow this sort of reordering ( In fact, in this example x++,y++ The instruction is divided into three steps , Here you just need to know the meaning of the expression ). But in multithreading, data dependency can't guarantee thread safety .

 

   Back to the instruction set created by the previous object ,2 and 3 Because there is no data dependency, instruction reordering may occur , So in multithreading , Maybe threads 1 In execution new Execute the instruction directly after the instruction 3, Threads 2 It's up to the 7 Line the first non empty judgment , At this point, because the object address is assigned , So the judgment is not empty , direct return, But the initialization instruction has not been executed yet , So the object just allocates space and hasn't created the object yet , The result is that the method still returns a null value ( This null The value indicates that the object at this position is not available, but the judgment is not empty ).

 

solve

  volatile  Keywords can prevent instruction reordering and ensure visibility , But because there's no guarantee of atomicity , So we still need to cooperate here synchronized  To use . About volatile In the multithreading foundation, it is said that , So the final code here is :

 1 public class SingletonDemo {
 2     private volatile static SingletonDemo singletonDemo = null;
 3     private SingletonDemo(){
 4     }
 5 
 6     public SingletonDemo getSingletonDemo(){
 7         if(singletonDemo == null){
 8             synchronized (SingletonDemo.class){
 9                 if(singletonDemo == null){
10                     singletonDemo = new SingletonDemo();
11                 }
12             }
13         }
14         return singletonDemo;
15     }
16 }

  

Add

   Other implementations of the singleton pattern :

Hungry Chinese style

   Because the hunghan style is that when the class is loaded, the object instance will be created and assigned , So it's safe in multithreading , So its advantage is that there is no thread safety problem , The disadvantage is that there is no advantage of delayed loading , For example, the singleton pattern object is loaded from the beginning , But it took a long time to use the program , Then it is created in the heap when it is loaded from the class , Until it's used , It takes up space all the time in the heap , If there are more than one singleton class of starving Han , It's invisible GC Number of occurrences . Reduce the performance of the program .

1、 Directly instantiate the starved Chinese style

public class Singleton1 {
    private static final Singleton1 INSTANCE=new Singleton1();
    
    private Singleton1() {
    }
    public static Singleton1 getSingleton() {
        return INSTANCE;
    }
}

characteristic : Simple and direct    

 

2、 Enumerative hungry Chinese

public enum Singleton12 {
    INSTANCE;
    public void aa() {            // Method to call 
    }
}

characteristic : Most succinct

 

3、 Static code block hungry han

public class Singleton13 {
    private static final Singleton13 INSTANCE;
    static {
        INSTANCE=new Singleton13();
    }
    public static Singleton13 getSingleton() {
        return INSTANCE;
    }
}

characteristic : You can add other operations during class initialization

 

Slacker type

   The lazy singleton pattern does not create an object until the method is called to get it , There will be thread safety issues , So it's more complicated , But because it's delayed loading , So there's the advantage of delayed loading .

1、DCL Slacker type

   Code as above .

 

2、 Static internal lazy type

public class Singleton22 {
    private Singleton22() {
        
    }
    
    private static class Inner{
        private static final Singleton22 INSTANCE=new Singleton22();
    }
    
    public static Singleton22 getInstance() {
        return Inner.INSTANCE;
    }
}

Compared with DCL The sluggard style is simpler , At the same time, there is no lock and unlock operation , More efficient .

版权声明
本文为[Meng Xin J]所创,转载请带上原文链接,感谢