1. 程式人生 > >雙重校驗鎖 為啥要用volatile修飾

雙重校驗鎖 為啥要用volatile修飾

public class Single {
    private static volatile Single single;
    public static Single getSingle(){
        if (single==null){
            synchronized (Single.class){
                if (single==null){
                    single=new Single();
                }
            }
        }
        return null;
    }
}

因為如果不用volatile修飾的話,在 single=new Single();會發生指令重排序,

Single的程式碼可以分解為三個部分

  1. 分配物件的記憶體空間
  2. 初始化物件
  3. 設定single指向記憶體空間

在JIT裡,可能會將2與3進行重排序,在單執行緒裡這裡並不會發生什麼問題,但是在多執行緒情況下,會出現下面的問題

時間

執行緒A

執行緒B

t1

A1:分配物件的記憶體空間

 

t2

A3:設定single指向記憶體空間

 

t3

 

B1:判斷single是否為空

t4

 

B2:由於single不為null,執行緒B將訪問single引用的物件

t5

A2:初始化該物件

 

t6

A4:訪問single引用的物件

 

A2與A3重排序後,會讓執行緒B在B1處判斷出single不為null,執行緒B接下來將訪問的single引用的物件是一個未初始化的物件。

所以用volatile修飾 single來就是禁止2與3的重排序,來保證執行緒安全的延遲初始化。