在 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
}
}
适用场景:
类名 | 适用类型 | 是否推荐 | 说明 |
---|---|---|---|
AtomicInteger | int | ✅ | 简单并发累加 |
AtomicLong | long | ✅ | 同上 |
LongAdder | long | ✅✅✅ | 高并发首选 |
DoubleAdder | double | ✅✅✅ | 浮点数累加 |
✅ 三、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
✅ 四、总结
类名 | 类型 | 线程安全 | 推荐场景 | 内部实现 |
---|---|---|---|---|
AtomicInteger | int | ✅ | 低并发、简单计数 | CAS |
AtomicLong | long | ✅ | 同上 | CAS |
LongAdder | long | ✅✅✅ | 高并发累加(推荐) | 分段CAS |
DoubleAdder | double | ✅✅✅ | 高并发浮点累加 | 分段CAS |
LongAccumulator | long | ✅✅ | 自定义操作(加、乘、max) | 分段CAS |
DoubleAccumulator | double | ✅✅ | 同上 | 分段CAS |
🧠 面试回答建议(简洁版)
在 Java 中,我使用过
AtomicInteger
、AtomicLong
和LongAdder
来实现线程安全的累加操作。其中,LongAdder
是 Java 8 引入的高性能累加器,适合高并发场景,因为它采用分段锁机制减少 CAS 冲突。对于更复杂的累加逻辑,我还使用过LongAccumulator
来自定义累加规则,比如求最大值或乘积等。
如果你在项目中使用过这些类,可以结合具体业务场景说明,比如统计请求次数、并发计数器、高并发计费系统等,这样面试官会更认可你的实战经验。
THE END