首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java volatile 關鍵字深度解析:多執行緒可見性保證與使用陷阱

     編輯:Java 相關知識

為什麼需要 volatile?

JVM 允許執行緒將共享變數快取於本地記憶體(暫存器/L1 Cache),導致「寫入執行緒更新主存,讀取執行緒仍讀到舊值」的可見性問題。volatile 強制:

  • 讀取時直接從主存載入。
  • 寫入時立即刷回主存。

從而確保任意時刻所有執行緒看到的值一致。

核心語義(JSR-133 / Java 5+)

  1. 可見性:對 volatile 變數的寫入,對後續讀取該變數的執行緒必定可見(happens-before)。
  2. 禁止指令重排:編譯器/處理器不會將 volatile 讀寫與普通讀寫重排序,保證程式順序語意。
  3. 非原子性:volatile long/double 讀寫非原子(32 位拆兩次),其餘基本型別原子;複合操作(i++、check-then-act)不保證原子,仍需 synchronized 或 Atomic*。

適用場景

  • 狀態旗標:volatile boolean shutdown = false;
  • 一次性發布:volatile Config config = null;(雙重檢查鎖定模式中必要)。
  • 獨立觀察變數:不參與不變條件的單一狀態值。

不適用場景

  • 複合動作(計數器、檢查後行動)——需鎖或原子類。
  • 已在 synchronized 區塊內的變數(鎖已提供可見性)。
  • 常數(final 已隱含可見性)。

效能考量

volatile 會阻擋 JIT 某些優化(如暫存器分配、指令重排),並觸發記憶體屏障指令。單次存取開銷約為普通讀寫的 2–3 倍,但遠低於鎖。高頻熱點路徑建議改用 AtomicLong 等無鎖結構。

程式碼範例:安全發布

class ConfigManager {
    private volatile Config current; // 發布時寫入 volatile
    public Config getConfig() { return current; } // 讀取無需同步
    public void reload(Config newCfg) { current = newCfg; }
}

總結

volatile 是「輕量級同步」利器,專解決可見性與有序性,不解決原子性。正確使用前提:寫入不依賴舊值、讀寫無不變條件關聯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved