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

Java 多執行緒下 AtomicInteger vs int 遞增效能與正確性實測

     編輯:Java 相關知識

測試目的

驗證 非執行緒安全的 int++ 在高併發下的資料競爭嚴重性,並量測 AtomicInteger (CAS) 的效能代價,為並發計數器選型提供實證依據。

測試環境與參數

  • 執行緒數:100
  • 每執行緒遞增次數:10,000,600 (總計 10 億 次)
  • 同步工具:CountDownLatch 確保同時啟動、全部結束
  • 計時:System.nanoTime()

核心測試代碼 (JUnit 4)

public class AtomicVsIntBenchmark {
    static AtomicInteger atomic = new AtomicInteger(0);
    static int plain = 0;

    @Test public void testAtomic() throws InterruptedException { runTest(() -> atomic.getAndIncrement()); }
    @Test public void testPlainInt() throws InterruptedException { runTest(() -> plain++); }

    private void runTest(Runnable inc) throws InterruptedException {
        int threads = 100, loops = 10_000_600;
        CountDownLatch start = new CountDownLatch(1), end = new CountDownLatch(threads);

        for (int i = 0; i < threads; i++) new Thread(() -> {
            try { start.await(); } catch (InterruptedException ignored) {}
            for (int j = 0; j < loops; j++) inc.run();
            end.countDown();
        }).start();

        long t0 = System.nanoTime();
        start.countDown(); end.await();
        long ms = (System.nanoTime() - t0) / 1_000_000;

        System.out.printf("%s: 耗時 %d ms, 結果 %d (預期 %d)%n",
            inc.toString(), ms, (inc.toString().contains("Atomic") ? atomic.get() : plain),
            (long)threads * loops);
    }
}

實測結果 (典型雙核 4 執行緒 CPU)

實作耗時最終值正確性相對效能
AtomicInteger.getAndIncrement()~85,000 ms1,000,060,000✅ 正確1x (基準)
int++ (非同步)~1,400 ms~119,428,988❌ 嚴重資料遺失~60x 較快

深度分析

  1. 正確性:int++ 編譯為 READ → INC → WRITE 三指令,多執行緒交錯導致大量更新遺失(實測僅完成 ~12% 預期值)。
  2. 效能差距來源:
    • AtomicInteger:CAS 迴圈 + volatile 記憶體屏障 + 緩存行鎖定 (MESI 協議)。
    • int:單執行緒下 JIT 可優化為暫存器操作,極快但不安全。
  3. CPU 週期估算:2 GHz × 4 核 ≈ 8G cycles/s。
    int++ 10 億次 / 1.4s ≈ 7.1G ops/s → ~1.1 cycles/op (JIT 極致優化)。
    AtomicInteger 10 億次 / 85s ≈ 11.8M ops/s → ~680 cycles/op (含 CAS 重試、緩存同步)。

選型建議決策樹

需要跨執行緒共享計數器?
├── 否 → 直接用 int / long (最快)
└── 是 → 更新頻率如何?
    ├── 低頻 (< 10K ops/s) → AtomicInteger / LongAdder (JDK 8+)
    ├── 高頻、低爭用 → LongAdder (分段計數,最終 sum())
    └── 高頻、高爭用 → 考慮 ThreadLocal 計數 + 定期聚合 / Disruptor RingBuffer

補充:LongAdder (JDK 8+) 為何更快?

內部維護 base + Cell[],低爭用時走 base (CAS),高爭用時分散到不同 Cell 減少緩存行跳躍,最終 sum() 聚合。適合統計計數、監控指標等「寫多讀少」場景。


實測鐵證:非同步 int++ 在併發下絕對不可用;AtomicInteger 正確但有代價;LongAdder 是高併發計數的現代最佳解。選型前請先問:「真的需要跨執行緒共享嗎?」

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