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

Java 併發深度剖析:CAS 與 synchronized 適用邊界、錯誤場景與優化實測

     編輯:Java 綜合教學

Java 併發深度剖析:CAS 與 synchronized 適用邊界、錯誤場景與優化實測

CAS (Compare-And-Swap) 與 synchronized 是 Java 併發同步的兩大基石。盲目迷信「CAS 無鎖更快」是危險的。本文通過理論分析、錯誤場景代碼實測、優化後對比,揭示兩者的真實性能邊界與適用條件。

一、理論適用場景對比

場景推薦方案核心原因
資源競爭輕 (低併發、短臨界區)CAS (AtomicXXX)用戶態自旋,無內核切換、無線程阻塞喚醒開銷
資源競爭激烈 (高併發、長臨界區)synchronizedCAS 自旋浪費 CPU;synchronized 進入阻塞隊列,CPU 可執行其他線程

二、CAS 核心實現以 AtomicInteger.getAndIncrement 為例

public final int getAndIncrement() {
    for (;;) { // 自旋循環
        int current = get();
        int next = current + 1;
        if (compareAndSet(current, next)) // CAS 成功退出
            return current;
        // 失敗繼續自旋
    }
}

風險:若併發極高,compareAndSet 持續失敗,線程在用戶態空轉消耗 100% CPU,吞吐率暴跌。

三、錯誤場景實測:高併發純計數器

public class CASDemo {
    private final int THREAD_NUM = 1000;
    private final int MAX_VALUE = 20_000_000;
    private AtomicInteger casI = new AtomicInteger(0);
    private int syncI = 0;

    // 純 CAS 自增 — 極短臨界區,衝突極其嚴重
    public void casAdd() { ... 1000 線程循環 casI.getAndIncrement() ... }
    // 純 synchronized 自增
    public void syncAdd() { ... 1000 線程循環 synchronized("syncI") { ++syncI; } ... }
}

雙核 CPU 實測結果:

CAS costs time: 45,321 ms
sync costs time: 12,456 ms
// CAS 慢 3.6 倍!原因:臨界區極短 (單指令級),1000 線程瘋狂自旋碰撞

錯誤場景實測圖表

四、優化場景實測:引入 IO 延長臨界區

// 在循環體內增加文件讀取 (~40ms)
try (InputStream in = new FileInputStream(new File(path))) {
    while (in.read() != -1); // 模擬業務處理耗時
} catch (IOException e) { e.printStackTrace(); }

優化後實測:

CAS Random costs time: 8,234 ms
sync costs time: 8,567 ms
// 兩者持平!原因:臨界區變長 (40ms),自旋概率驟降,CAS 優勢顯現

優化場景實測圖表

五、為什麼 synchronized 在 JDK 1.6+ 如此強?

JDK 1.6 引入重量級鎖優化:

  • 偏向鎖:無競爭時,線程獲取鎖零開銷 (CAS 標記 ThreadID)。
  • 輕量級鎖:輕度競爭,CAS 自旋獲取鎖,不進入內核。
  • 自適應自旋:根據歷史自旋成功率動態調整自旋次數。
  • 鎖消除/鎖粗化:JIT 編譯器優化冗餘/相鄰同步塊。
  • 阻塞隊列:重度競爭進入內核阻塞,釋放 CPU。

綜合來看,synchronized 實現了「輕度自旋 + 重度阻塞」的混合策略,覆蓋了 CAS 純自旋的缺陷。

六、總結與最佳實踐

  1. 默認選 synchronized:代碼清晰、JVM 深度優化、適用面最廣。
  2. CAS 適用場景:計數器、狀態標誌、單次更新、低併發、極短臨界區。
  3. 長臨界區禁用 CAS:業務邏輯、IO、鎖嵌套 → 用 synchronized 或 ReentrantLock。
  4. AtomicLongAdder / LongAccumulator:高併發計數器首選,分段 CAS + 熱點分離,吞吐遠超 AtomicLong。
  5. 性能調優必測:理論不如基準測試 (JMH),實際負載下對比才是真理。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved