雙重校驗鎖 為啥要用volatile修飾
阿新 • • 發佈:2018-12-01
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的程式碼可以分解為三個部分
- 分配物件的記憶體空間
- 初始化物件
- 設定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的重排序,來保證執行緒安全的延遲初始化。