Skip to content

LongAdder

你知道吗?AtomicLong 在高并发场景下,100 个线程同时累加,可能会执行数万次 CAS 操作。

因为每个线程都在自旋、重试、失败、再重试...

LongAdder 就是来解决这个问题的——它让每个线程累加到自己的"分段",最后汇总。

为什么需要 LongAdder

先看一个性能对比:

java
public class PerformanceComparison {

    public static void main(String[] args) throws InterruptedException {
        int threads = 100;
        int ops = 100000;

        // AtomicLong
        AtomicLong atomicLong = new AtomicLong(0);
        long start = System.nanoTime();

        for (int i = 0; i < threads; i++) {
            new Thread(() -> {
                for (int j = 0; j < ops; j++) {
                    atomicLong.incrementAndGet();
                }
            }).start();
        }

        Thread.sleep(5000);
        System.out.println("AtomicLong: " + atomicLong.get() +
            ", 耗时: " + (System.nanoTime() - start) / 1_000_000 + "ms");

        // LongAdder
        LongAdder longAdder = new LongAdder();
        start = System.nanoTime();

        for (int i = 0; i < threads; i++) {
            new Thread(() -> {
                for (int j = 0; j < ops; j++) {
                    longAdder.increment();
                }
            }).start();
        }

        Thread.sleep(5000);
        System.out.println("LongAdder: " + longAdder.sum() +
            ", 耗时: " + (System.nanoTime() - start) / 1_000_000 + "ms");
    }
}

在高竞争下,LongAdder 通常比 AtomicLong 快 数倍到数十倍

工作原理

┌────────────────────────────────────────────────────┐
│                   LongAdder 分段累加                     │
├────────────────────────────────────────────────────┤
│                                                      │
│  传统 CAS:所有线程争抢同一个变量                      │
│  ┌─────────────────────────────────────────────┐    │
│  │         AtomicLong (全局竞争)                  │    │
│  │    T1 ──► [  ████████░░░░ ] T2 ──►        │    │
│  │    T3 ──► [  ████████████ ] T4 ──►        │    │
│  │    T5 ──► [  ██████████░░ ] T6 ──►        │    │
│  └─────────────────────────────────────────────┘    │
│                    激烈竞争!                         │
│                                                      │
│  LongAdder:每个线程累加到自己的 Cell                  │
│  ┌─────────────────────────────────────────────┐    │
│  │              LongAdder                       │    │
│  │  ┌─────────┬─────────┬─────────┬─────────┐ │    │
│  │  │ Cell[0] │ Cell[1] │ Cell[2] │ Cell[3] │ │    │
│  │  │ T1,T2   │ T3,T4   │ T5,T6   │   T7    │ │    │
│  │  │ 累加到这 │ 累加到这 │ 累加到这 │ 累加到这 │ │    │
│  │  └─────────┴─────────┴─────────┴─────────┘ │    │
│  └─────────────────────────────────────────────┘    │
│                    分段并行!                         │
│                                                      │
└────────────────────────────────────────────────────┘

核心思想:把一个value拆成多个,每个线程累加到自己的"分段",最后求和。

代码演示

基础用法

java
public class LongAdderDemo {

    private static final LongAdder counter = new LongAdder();

    public static void main(String[] args) throws InterruptedException {
        int threadCount = 100;

        for (int i = 0; i < threadCount; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    counter.increment();
                }
            }).start();
        }

        Thread.sleep(2000);
        System.out.println("计数结果: " + counter.sum());  // 应该是 100000
    }
}

常用方法

java
public class LongAdderMethods {

    private static final LongAdder adder = new LongAdder();

    public static void main(String[] args) {
        // increment() - 递增1
        adder.increment();
        System.out.println("increment(): " + adder.sum());  // 1

        // decrement() - 递减1
        adder.decrement();
        System.out.println("decrement(): " + adder.sum());  // 0

        // add(long x) - 增加指定值
        adder.add(100);
        System.out.println("add(100): " + adder.sum());  // 100

        // sum() - 获取当前总和
        adder.increment();
        adder.increment();
        System.out.println("sum(): " + adder.sum());  // 102

        // sumThenReset() - 获取总和并重置
        long sum = adder.sumThenReset();
        System.out.println("sumThenReset(): " + sum);  // 102
        System.out.println("重置后: " + adder.sum());   // 0

        // reset() - 重置(线程不安全)
        adder.add(50);
        adder.reset();
        System.out.println("reset() 后: " + adder.sum());  // 0
    }
}

实际应用:API 统计

java
public class ApiStatistics {

    private final LongAdder totalRequests = new LongAdder();
    private final LongAdder successCount = new LongAdder();
    private final LongAdder errorCount = new LongAdder();
    private final LongAdder latencyAdder = new LongAdder();

    public void recordRequest(boolean success, long latencyMs) {
        totalRequests.increment();
        if (success) {
            successCount.increment();
        } else {
            errorCount.increment();
        }
        latencyAdder.add(latencyMs);
    }

    public double getAverageLatency() {
        long total = latencyAdder.sum();
        long count = totalRequests.sum();
        return count > 0 ? (double) total / count : 0;
    }

    public void printStats() {
        System.out.println("=== API 统计 ===");
        System.out.println("总请求数: " + totalRequests.sum());
        System.out.println("成功数: " + successCount.sum());
        System.out.println("失败数: " + errorCount.sum());
        System.out.println("平均延迟: " + getAverageLatency() + "ms");
    }

    public static void main(String[] args) {
        ApiStatistics stats = new ApiStatistics();
        Random random = new Random();

        // 模拟 10000 次请求
        for (int i = 0; i < 10000; i++) {
            boolean success = random.nextInt(100) > 5;  // 95% 成功率
            long latency = 10 + random.nextInt(100);
            stats.recordRequest(success, latency);
        }

        stats.printStats();
    }
}

LongAccumulator:自定义累加

LongAdder 的增强版,支持自定义累加函数:

java
public class LongAccumulatorDemo {

    public static void main(String[] args) {
        // 求最大值
        LongAccumulator maxAccumulator = new LongAccumulator(
            Long::max,           // 累加函数
            Long.MIN_VALUE       // 初始值
        );

        maxAccumulator.accumulate(10);
        maxAccumulator.accumulate(5);
        maxAccumulator.accumulate(20);
        System.out.println("最大值: " + maxAccumulator.get());  // 20

        // 求最小值
        LongAccumulator minAccumulator = new LongAccumulator(
            Long::min,
            Long.MAX_VALUE
        );

        minAccumulator.accumulate(10);
        minAccumulator.accumulate(5);
        minAccumulator.accumulate(20);
        System.out.println("最小值: " + minAccumulator.get());  // 5
    }
}

LongAdder vs AtomicLong

特性AtomicLongLongAdder
原理CAS 自旋分段累加
竞争全局竞争分段并行
性能高竞争时差高竞争时优
精度精确精确(sum时汇总)
内存一个变量多个 Cell
sum()get()可能非原子

注意事项

  1. sum() 可能不精确:sum() 在汇总过程中可能有新值正在累加,结果是近似值
  2. 不适合需要精确中间值的场景:LongAdder 设计目标是吞吐量
  3. 适合统计场景:QPS、计数、延迟统计
  4. reset() 线程不安全:多线程下 reset() 可能丢失其他线程的累加

选择建议

需要精确值吗?
  ├── 是 ──► AtomicLong
  └── 否 ──► 极高并发吗?
              ├── 是 ──► LongAdder
              └── 否 ──► AtomicLong

基于 VitePress 构建