当前位置:网站首页>Multithreading tutorial (XXI) double checked locking problem

Multithreading tutorial (XXI) double checked locking problem

2022-06-11 05:29:00 Have you become a great God today

Multithreading tutorial ( The 21st )double-checked locking problem

One 、double-checked locking Imperfect examples of

With the famous double-checked locking Single instance mode as an example

public final class Singleton {
    
    private Singleton() {
     }
    private static Singleton INSTANCE = null;
    public static Singleton getInstance() {
     
        if(INSTANCE == null) {
     // t2
            //  The first visit synchronizes , And then the use did not  synchronized
            synchronized(Singleton.class) {
    
                if (INSTANCE == null) {
     // t1
                    INSTANCE = new Singleton();
                } 
            }
        }
        return INSTANCE;
    }
}

The above implementation features are :

  • Laziness

  • For the first time to use getInstance() Only use synchronized Lock , There is no need to lock it for subsequent use

  • There is an implied , But the key point is : first if Used INSTANCE Variable , It's outside the sync block

But in a multithreaded environment , There is something wrong with the code above ,getInstance The bytecode corresponding to the method is :

0: getstatic #2 // Field INSTANCE:Lcn/itcast/n5/Singleton;
3: ifnonnull 37
6: ldc #3 // class cn/itcast/n5/Singleton
8: dup
9: astore_0
10: monitorenter
11: getstatic #2 // Field INSTANCE:Lcn/itcast/n5/Singleton;
14: ifnonnull 27
17: new #3 // class cn/itcast/n5/Singleton
20: dup
21: invokespecial #4 // Method "<init>":()V
24: putstatic #2 // Field INSTANCE:Lcn/itcast/n5/Singleton;
27: aload_0
28: monitorexit
29: goto 37
32: astore_1
33: aload_0
34: monitorexit
35: aload_1
36: athrow
37: getstatic #2 // Field INSTANCE:Lcn/itcast/n5/Singleton;
40: areturn

among

  • 17 Represents the creation object , Stack object references // new Singleton

  • 20 Represents copying an object reference // Refer to the address

  • 21 Means to use an object reference , Call constructor

  • 24 Means to use an object reference , Assign a value to static INSTANCE

Maybe jvm It will be optimized to : Execute first 24, Re execution 21. If two threads t1,t2 Execute according to the following time series :

 Insert picture description here

The key lies in 0: getstatic This line of code is in monitor Out of control , It's like the irregular person in the previous example , You can cross monitor Read

INSTANCE The value of the variable

At this time t1 The constructor has not been fully executed yet , If you need to perform a lot of initialization operations in the constructor , that t2 What you get will be an early

Single case after initialization

Yes INSTANCE Use volatile Can be modified , Command rearrangement can be disabled , But pay attention to JDK 5 The above version of volatile It really works

Two 、double-checked locking The correct use of

private Singleton() {
     }
private static volatile Singleton INSTANCE = null;
public static Singleton getInstance() {
    
    //  Instance not created , To get inside  synchronized Code block 
    if (INSTANCE == null) {
     
        synchronized (Singleton.class) {
     // t2
            //  There may be other threads that have created instances , So again 
            if (INSTANCE == null) {
     // t1
                INSTANCE = new Singleton();
            }
        }
    }
    return INSTANCE;
}
}

I can't see it in the bytecode volatile The effect of the command

// ------------------------------------->  Join in  INSTANCE  Variable read barrier 
0: getstatic #2 		// Field INSTANCE:Lcn/itcast/n5/Singleton;
3: ifnonnull 37
6: ldc #3 				// class cn/itcast/n5/Singleton
8: dup
9: astore_0
10: monitorenter ----------------------->  Guaranteed atomicity 、 visibility 
11: getstatic #2 		// Field INSTANCE:Lcn/itcast/n5/Singleton;
14: ifnonnull 27
17: new #3 				// class cn/itcast/n5/Singleton
20: dup
21: invokespecial #4 	// Method "<init>":()V
24: putstatic #2 		// Field INSTANCE:Lcn/itcast/n5/Singleton;
// ------------------------------------->  Join in  INSTANCE  Variable write barrier 
27: aload_0
28: monitorexit ------------------------>  Guaranteed atomicity 、 visibility 
29: goto 37
32: astore_1
33: aload_0
34: monitorexit
35: aload_1
36: athrow
37: getstatic #2 		// Field INSTANCE:Lcn/itcast/n5/Singleton;
40: areturn

As shown in the notes above , Reading and writing volatile Variable will be added to the memory barrier (Memory Barrier(Memory Fence)), Make sure the following two points :

  • visibility

    • Write barriers (sfence) Ensure... Before the barrier t1 Changes to shared variables , All synchronized to main memory .
    • And the reading barrier (lfence) Ensure that after this barrier t2 Reading shared variables , Loading is the latest data in main memory
  • Orderliness

    • The write barrier ensures that when instructions are reordered , Don't put the code before the write barrier behind the write barrier

    • The read barrier ensures that when instructions are reordered , The code after the read barrier is not placed before the read barrier

At the bottom is the use of... When reading and writing variables lock Instruction to multicore CPU Visibility and order between

 Insert picture description here

In the picture x Representative band barrier .

On board volatile The role of is ’ Call constructor ’ Operations of cannot be reordered to ‘ assignment ’ Back , You can avoid getting the class without running the constructor .

原网站

版权声明
本文为[Have you become a great God today]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/03/202203020539055963.html