volatile 變量的值,對其他線程立即可見。實現:寫入時刷新到主內存,讀取時從主內存加載(繞過 CPU 緩存)。volatile 讀寫前後的指令不會被重排序(JMM Happens-Before 規則)。不保證原子性:volatile int i; i++; 仍非原子(讀-改-寫三步),需配合 AtomicInteger 或 synchronized。
volatile 插入內存屏障:// 寫屏障:StoreStore + StoreLoad
volatileVar = value; // 確保之前寫入不被重排到此後,且立即刷新主存
// 讀屏障:LoadLoad + LoadLoad
x = volatileVar; // 確保此讀不被重排到之前,且從主存讀取最新值
public class Singleton {
private volatile static Singleton instance; // 禁止指令重排:分配內存 -> 初始化 -> 賦值引用
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查(無鎖,性能)
synchronized (Singleton.class) {
if (instance == null) { // 第二次檢查
instance = new Singleton(); // 非原子:1.分配 2.初始化 3.賦值
}
}
}
return instance;
}
}
無 volatile 時,步驟 2/3 可能重排,導致其他線程看到半初始化對象。
| 場景 | 是否適合 | 說明 |
|---|---|---|
| 狀態標誌位 | ✅ 完美 | volatile boolean running、volatile boolean shutdown |
| 單次發布 (Safe Publication) | ✅ 適合 | 對象構造完成後發布引用,配合 final 字段保證不可變對象安全發布 |
| 獨立觀察 (One Writer, Many Readers) | ✅ 適合 | 配置熱更新、計數器快照讀(寫入用 CAS/鎖) |
| 複合操作 (i++, check-then-act) | ❌ 不適合 | 需 Atomic* / synchronized / Lock |
| 多變量不變式關聯 | ❌ 不適合 | 需鎖保證多變量原子性 |
volatile:輕量級,無阻塞,僅保證可見性+有序性,適用單變量。synchronized:重量級(早期),可重入,保證原子性+可見性+有序性,適用臨界區/多變量。public class CasCounter {
private volatile int value; // 可見性
public int increment() {
int prev, next;
do {
prev = value;
next = prev + 1;
} while (!UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, prev, next)); // 原子性
return next;
}
}
實際開發直接用 AtomicInteger 或 LongAdder。