java lock and double check

Double check lock/double check lock double-layer anti-air judgment has been troubled for a long time. Instance

public class Singleton {
    private volatile static Singleton singleton;

  //私有构造函数避免调用
    private Singleton (){}
    public static Singleton getSingleton() {

    // 先判断对象是否创建过
        if (singleton == null) {

        //类对象加锁
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                    //字节码层
                    //JIT CPU 可能对如下指令进行重排序
                    // 1.分配空间
                    // 2.初始化
                    // 3.引用赋值
                    如果指令重排后指令如下:
                    //1.分配空间
                    //3.引用赋值 如果在当前指令执行完后,有其他线程获取到实例,将拿到未初始化的实例;
                    //2. 初始化
                }
            }
        }
        return singleton;
    }
}


Explanation: When A and B call getSingleton at the same time, it is judged that the first if is empty. At this time, A gets the lock and performs the second level if judgment. The condition is established and an object is new;

B waits in the outer layer, A is created, the lock is released, B gets the lock, and the second level if judgment is performed. The condition is not established, and the lock is released. When C calls getSingleton, the first level of judgment is not established, and the singleton object is returned directly to avoid entering the lock and reduce performance overhead.

Further understanding: two of them are empty, the first empty is to reduce the number of times to enter the synchronization code block in the case of multithreading, and the second empty is to prevent multithreading (A, B in the case of two threads) , B calls the getSingleton method at the same time, and at the same time, enters the first layer if(singleton==null){}. Under race conditions, if A obtains the object lock, enters the synchronous code block, and B blocks waiting, waiting After the instance object is created and the lock is released, B enters the synchronization code block, but at this time the second level if(singleton==null){} judges that singleton is not empty, and returns singleton directly);

Summary: There are two statements to determine whether it is empty. The first time is to improve efficiency and avoid executing synchronized code blocks each time. The second time is to avoid the insecurity caused by multithreading. When two threads judge that the first one is empty at the same time, they will all enter the synchronization code block one after another. At this time, if there is no second empty condition, multiple instances will be created.

volite keywords:

It is necessary to use volatile keyword modification

This code is actually divided into three steps:

singleton = new Singleton();

  1. Allocate memory space for singleton
  2. Initialize singleton 
  3. Point the singleton to the allocated memory address.
    However, jvm has the characteristics of instruction rearrangement, and the execution order may change, not in the order of 123, but may be 132, which will cause a thread to obtain an uninitialized instance
    such as: t1 is executed 13. At this time, after t2 calls getInstance(), it is found that the singleton is no longer empty, so singleton is returned, but at this time, the singleton has not been initialized
    volatile and the jvm instruction rearrangement can be prohibited to ensure that it can be normal in a multithreaded environment run

Want to know more: Recommend

In-depth understanding of the synchronized implementation principle of Java concurrency

https://blog.csdn.net/javazejian/article/details/72828483

 

reference:

https://blog.csdn.net/jlnu0812407/article/details/102836187

https://blog.csdn.net/faye_1008/article/details/90296173

Guess you like

Origin blog.csdn.net/JHON07/article/details/103048352