Double check singleton mode, why do singleton objects need to add volatile keyword?

Code:

class Singleton{
    private volatile static Singleton instance = null;
    
    private Singletion{}

    public static Singleton getInstance(){
        if(instance==null){                        //#1
            synchronized(Singleton.class){         //#2
                if(instance==null){                //#3
                    instance = new Singletion();   //#4
                }else{
                    System.out.println("test");    //#5
                }
            }
        }
        return instance;
    }

}

 

Why do singleton objects need to add the volatile keyword? There are two reasons:

(1) Ensure visibility:

如果"private static Singleton instance = null;":

1. Thread1 enters #1, then thread1's instance is null, thread1 gives up CPU resources to thread2.
2. Thread2 enters #1, then thread2's instance is null, thread2 gives up CPU resources to thread1.
3. Thread1 will Execute #2, #3, #4 in turn, and finally instantiate instance in thread1. Thread1 finishes execution and gives up CPU resources to thread2.
4. Thread2 then runs #1, and when it reaches #3, because the instance obtained in #1 is still null (and the latest one from thread1 was not obtained in time), so Thread2 will still execute #3, #4.
5. Finally, both thread1 and thread2 instantiate instance.

 

如果"private volatile static Singleton instance = null;":

1. Thread1 enters #1, then the instance of thread1 is null (the java memory model will copy instance(null) from the main memory to thread1), thread1 gives up CPU resources to thread2.
2. Thread2 enters #1, this When the instance of thread2 is null (the java memory model will copy instance(null) from main memory to thread2), thread2 will give up CPU resources to thread1.
3. Thread1 will execute #2, #3, #4 in turn, and finally Instance is instantiated in thread1 (because it is a volatile modified variable, it will be synchronized to the variable in the main memory immediately). After thread1 is executed, it gives up CPU resources to thread2.
4. thread2 then #1 runs down, and when it reaches #3, it will copy an instance (!=null) from the main memory again, so thread2 ran directly to # 5.
5. Finally thread2 will no longer instantiate instance repeatedly.

 

(2) Prevent reordering:

In the singleton mode, Instance instance = new Instance(); This code is not an atomic operation, it can be divided into three steps of atomic instructions:

1. Allocate memory address;

2.new an Instance object;

3. Assign the memory address to instance;

In order for the CPU to improve execution efficiency, the sequence of these three operations can be 123 or 132. If the order is 132, when the memory address is assigned to inst, the singleton object is not new on the memory address pointed to by inst. At this time, if you get the instance, it is actually empty, and a null pointer exception will be reported.

Guess you like

Origin blog.csdn.net/u012906122/article/details/103414518