在「Java 併發程式設計」系列中,我們已介紹 synchronized、鎖優化、線程協作。本文聚焦 volatile——Java 提供的輕量級同步機制,解決可見性與有序性問題,但不保證複合操作的原子性。理解其底層原理(happens-before、記憶體屏障),是寫出正確高效併發程式的關鍵。
| 特性 | volatile 能否保證 | 說明 |
|---|---|---|
| 可見性 | ✅ 是 | 寫入立即刷新主記憶體,讀取強制從主記憶體載入 |
| 有序性 | ✅ 是 | 禁止編譯器/處理器對 volatile 變數的指令重排序 |
| 原子性 | ⚠️ 部分 | 單次讀/寫(含 long/double)原子;i++ 等複合操作不保證 |
誤區警示:許多開發者以為加上 volatile 就能保證線程安全,實則僅適用於「寫入不依賴當前值」且「不參與不變式」的場景。
public class Singleton {
public static volatile Singleton instance; // 關鍵:禁止重排序
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查
synchronized (Singleton.class) { // 加鎖
if (instance == null) { // 第二次檢查
instance = new Singleton(); // 非原子:分配→初始化→賦值
}
}
}
return instance;
}
}
原理:new Singleton() 實際分三步:① 分配記憶體 ② 初始化物件 ③ 將參考指向記憶體。處理器可能重排為 ①→③→②,導致其他線程見到「非 null 但未初始化」的物件。volatile 禁止此重排序。
class VolatileTest {
int a = 1, b = 2; // 非 volatile
void change() { a = 3; b = a; }
void print() { System.out.println("b=" + b + ";a=" + a); }
}
多線程並發執行時,可能出現 b=3;a=1(a 寫入未對其他線程可見)。將 a、b 改為 volatile 後,該異常結果消失。
JLS 17.7 規定:非 volatile 的 long/double 可能被拆為兩次 32 位操作,導致「撕裂讀取」。volatile 強制單次原子讀寫。
| Can Reorder | 第 2 操作 | Normal Load | Normal Store | Volatile Load | Volatile Store |
|---|---|---|---|---|---|
| 第 1 操作 | Normal Load | No | |||
| Normal Store | No | No | |||
| Volatile Load | No | No | No | No | |
| Volatile Store | No | No | No | No |
結論:volatile 讀/寫不可與任何操作重排序,形成強順序點。
JVM 透過插入處理器指令屏障實現上述語義:
| 屏障類型 | 指令序列 | 作用 |
|---|---|---|
| LoadLoad | Load1 → LoadLoad → Load2 | 確保 Load2 能見到 Load1 讀取的資料 |
| StoreStore | Store1 → StoreStore → Store2 | 確保 Store1 對其他處理器可見後再執行 Store2 |
| LoadStore | Load1 → LoadStore → Store2 | 確保 Store2 前能訪問 Load1 讀取的資料 |
| StoreLoad | Store1 → StoreLoad → Load2 | 確保 Store1 對其他處理器可見後再執行 Load2(最昂貴) |
插入策略:
int a, b; volatile int v, u;
void f() {
int i, j;
i = a; j = b; // 普通讀
i = v; // LoadLoad
j = u; // LoadStore
a = i; b = j; // 普通寫
v = i; // StoreStore
u = j; // StoreLoad
i = u; // LoadLoad + LoadStore
j = b; a = i;
}
僅當同時滿足以下條件時,可用 volatile 替代 synchronized:
否則請使用 synchronized、Lock 或 Atomic* 類別。