首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java volatile 關鍵字:不能保證原子性與線程安全的深度解析

     編輯:程式設計綜合問答

核心結論

volatile 保證:可見性(寫入對其他線程立即可見)、有序性(禁止指令重排序)。
不保證:原子性(複合操作不可分割)。

為什麼不保證原子性?

多 CPU 核心架構下:

  1. 線程 A 讀取 volatile int x 到寄存器
  2. 線程 A 修改寄存器值 x+1
  3. 寫回主存前,線程 B 也讀取了舊值 x
  4. 線程 B 修改並寫回 x+1
  5. 線程 A 寫回 x+1(覆蓋 B 的結果)
  6. 結果:兩次遞增,值只加 1

volatile 強制每次讀寫主存,但「讀-改-寫」三步仍可被交叉執行,無法合併為單一原子指令。

代碼演示

class Counter {
    volatile int count = 0;
    public void increment() { count++; } // 非原子!
}

// 1000 個線程各遞增 1000 次,預期 1,000,000,實際遠小於此

volatile 適用場景 vs 不適用場景

保證原子性的正確方案

  1. AtomicInteger:atomic.incrementAndGet() (CAS 底層)
  2. synchronized:鎖住複合操作
  3. Lock:ReentrantLock 精細控制
  4. ThreadLocal:避免共享

內存模型視角 (JMM)

  • volatile 插入 LoadLoad、LoadStore、StoreStore 屏障,禁止重排序
  • 但無 StoreLoad 屏障(需 synchronized 或 Lock),故無法保證「寫後讀」原子性
  • 單個 volatile 讀/寫是原子的 (32位以基本類型),但複合操作非原子

總結

volatile = 輕量級同步,適用於單一變量的狀態標記。任何「讀取-計算-寫入」模式的複合操作,必須用原子類或鎖。誤以為 volatile 能解決計數器線程安全是經典陷阱。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
適用 (單一讀/寫)不適用 (複合操作)
狀態標誌:volatile boolean running = true;計數器:count++
單次賦值:volatile int config = loadConfig();檢查後行動:if (x > 0) x--;
雙重檢查鎖模式中的實例引用累加/累減/複雜邏輯