面试题:你使用过 Java 的累加器吗?

在 Java 中,“累加器”(Accumulator)通常指的是用于多线程环境下高效执行累加操作的并发工具类。Java 提供了多种方式来实现累加器,其中最常用的是:


✅ 一、AtomicInteger / AtomicLong

这是 java.util.concurrent.atomic 包下的类,使用 CAS(Compare-And-Swap) 实现线程安全的原子操作。

示例:

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    private static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet(); // 原子累加
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet();
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Counter value: " + counter.get()); // 应该输出 2000
    }
}

优点:

  • 简单易用
  • 线程安全

缺点:

  • 在高并发下,CAS 失败重试可能导致性能下降。

✅ 二、LongAdder / DoubleAdder(推荐)

这是 Java 8 引入的类,位于 java.util.concurrent.atomic 包中,专为高并发累加设计。

为什么使用 LongAdder

  • LongAdder 内部维护了一个分段累加数组(cells),每个线程只更新自己的槽位(cell),最后通过 sum() 汇总,从而减少 CAS 冲突
  • 在并发高的场景下,性能远超 AtomicLong

示例:

import java.util.concurrent.atomic.LongAdder;

public class LongAdderExample {
    private static LongAdder counter = new LongAdder();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.add(1); // 线程安全的累加
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.add(1);
            }
        });

        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("Counter value: " + counter.sum()); // 输出 2000
    }
}

适用场景:

类名适用类型是否推荐说明
AtomicIntegerint简单并发累加
AtomicLonglong同上
LongAdderlong✅✅✅高并发首选
DoubleAdderdouble✅✅✅浮点数累加

✅ 三、Accumulator(函数式累加)

Java 8 还提供了两个函数式接口:

  • LongAccumulator
  • DoubleAccumulator

它们可以自定义累加函数,比如最大值、最小值、乘积等。

示例:

import java.util.concurrent.atomic.LongAccumulator;

public class LongAccumulatorExample {
    public static void main(String[] args) {
        // 累加器:自定义操作函数(这里是加法)
        LongAccumulator accumulator = new LongAccumulator((x, y) -> x + y, 0);

        accumulator.accumulate(10);
        accumulator.accumulate(20);

        System.out.println("Result: " + accumulator.get()); // 输出 30
    }
}

自定义操作(如最大值):

LongAccumulator maxAccumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);
maxAccumulator.accumulate(100);
maxAccumulator.accumulate(200);
System.out.println("Max: " + maxAccumulator.get()); // 输出 200

✅ 四、总结

类名类型线程安全推荐场景内部实现
AtomicIntegerint低并发、简单计数CAS
AtomicLonglong同上CAS
LongAdderlong✅✅✅高并发累加(推荐)分段CAS
DoubleAdderdouble✅✅✅高并发浮点累加分段CAS
LongAccumulatorlong✅✅自定义操作(加、乘、max)分段CAS
DoubleAccumulatordouble✅✅同上分段CAS

🧠 面试回答建议(简洁版)

在 Java 中,我使用过 AtomicIntegerAtomicLongLongAdder 来实现线程安全的累加操作。其中,LongAdder 是 Java 8 引入的高性能累加器,适合高并发场景,因为它采用分段锁机制减少 CAS 冲突。对于更复杂的累加逻辑,我还使用过 LongAccumulator 来自定义累加规则,比如求最大值或乘积等。


如果你在项目中使用过这些类,可以结合具体业务场景说明,比如统计请求次数、并发计数器、高并发计费系统等,这样面试官会更认可你的实战经验。

THE END
喜欢就支持一下吧
点赞11 分享