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

Java volatile 關鍵字原理與多核心程式設計技巧:CAS、原子類別完整指南

     編輯:Java 相關知識

volatile 語義與原理

  • 可見性:寫入立即刷新至主記憶體,讀取直接從主記憶體載入
  • 禁止指令重排:編譯器/CPU 不會重排 volatile 讀寫與普通讀寫
  • 不保證原子性:volatile int i; i++; 非原子操作!

為何 volatile 比 synchronized 輕量?

  • 無鎖開銷,無上下文切換
  • 僅影響單一變數,範圍最小
  • 適合「寫入單一、讀取多執行緒」場景

競態條件示範

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

// 100 執行緒各增 1000 次,結果 < 100000
// 原因:count++ = 讀取 → 加一 → 寫入,中間可被打斷

解決方案:CAS (Compare-And-Swap)

CPU 硬體指令:cmpxchg (x86)、ldrex/strex (ARM)。

// 邏輯:若記憶體值 == 預期值,則設為新值,否則失敗
boolean compareAndSet(int expect, int update) {
    // 原子執行,無需鎖
}

Java 原子類別完整應用

// 基本型別
AtomicInteger ai = new AtomicInteger(0);
ai.incrementAndGet();        // 原子遞增
ai.getAndAdd(5);             // 原子加法並取舊值
ai.compareAndSet(10, 20);    // CAS 更新

// 陣列
AtomicIntegerArray arr = new AtomicIntegerArray(10);
arr.getAndIncrement(0);

// 物件參考
AtomicReference ref = new AtomicReference<>("init");
ref.compareAndSet("init", "updated");

// 累加器 (Java 8+ 高併發優化)
LongAdder adder = new LongAdder();
adder.increment(); // 內部分段,極高吞吐
long sum = adder.sum();

ABA 問題與解決

CAS 檢查值相同但中間被改過:A→B→A。

// 解決:帶版本號的原子參考
AtomicStampedReference asr = 
    new AtomicStampedReference<>("A", 0);
// CAS 時同時檢查版本號
asr.compareAndSet("A", "B", 0, 1);

volatile 適用場景總結

場景適用替代方案
狀態旗標 (running, stopped)✅ 完美-
單次發布 (DCL 單例)✅ 配合 final-
計數器❌ 非原子AtomicInteger, LongAdder
複合操作 (check-then-act)❌ 需鎖synchronized, Lock
獨立觀察值✅ 良好-

效能比較 (高併發)

// 吞吐量排序 (高→低)
LongAdder > AtomicLong > synchronized > ReentrantLock
// 延遲排序 (低→高)
volatile 讀寫 ≈ 普通讀寫 < CAS < synchronized
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved