Java 原子类LongAccumulator自定义累加器
下文笔者讲述java中 LongAccumulator 自定义累加器的简介说明,如下所示
LongAccumulator简介
`LongAccumulator` 是 JDK 8 新增的原子累加类,
相比 `AtomicLong` 更灵活、高并发下性能更优,
核心特性如下:
1. 自定义累加规则:
不再局限于简单的“加 1/加 N”,
可通过 `LongBinaryOperator` 自定义任意二元累加逻辑(如累加、取最大值、取最小值、乘法等);
2. 分段累加优化:高并发下会将累加操作分散到多个分段变量(cell),
最后汇总结果,避免 `AtomicLong` 的 CAS 竞争瓶颈;
3. 初始值可控:支持指定累加的初始基准值,
而非固定从 0 开始;
4. 原子性保证:底层基于 CAS + 自旋 + 分段锁(Cells 数组)实现,
保证自定义累加逻辑的线程安全。
LongBinaryOperator核心接口
自定义累加规则的核心
是实现 `LongBinaryOperator` 函数式接口,
其唯一方法定义如下:
// left:当前累加器的已有值(或分段变量的当前值)
// right:本次要累加的输入值
long applyAsLong(long left, long right);
通过实现该方法
你可以定义任意的“已有值 + 输入值”的计算规则
(如取最大值、累加后取模、乘法等)。
LongAccumulator 基础使用(对比理解自定义)
先看基础用法(以“累加求和”为例),
对比理解自定义逻辑的实现方式:
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;
public class LongAccumulatorBasicDemo {
public static void main(String[] args) {
// 1. 定义累加规则:left(已有值) + right(输入值)(等价于AtomicLong的addAndGet)
LongBinaryOperator addOperator = (left, right) -> left + right;
// 2. 创建LongAccumulator:参数1=累加规则,参数2=初始值
LongAccumulator accumulator = new LongAccumulator(addOperator, 0);
// 3. 原子累加操作
accumulator.accumulate(10); // 0 + 10 = 10
accumulator.accumulate(20); // 10 + 20 = 30
// 4. 获取最终结果
System.out.println("累加结果:" + accumulator.get()); // 输出 30
// 5. 重置累加器(JDK 1.8+)
accumulator.reset();
System.out.println("重置后结果:" + accumulator.get()); // 输出 0
}
}
自定义“取最大值”累加器
场景:多线程竞争下,原子性记录输入值的最大值
(替代手动加锁的最大值统计)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;
public class MaxLongAccumulatorDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 自定义累加规则:取left(已有值)和right(输入值)的最大值
LongBinaryOperator maxOperator = (left, right) -> Math.max(left, right);
// 2. 初始值设为Long.MIN_VALUE(确保第一个输入值能覆盖初始值)
LongAccumulator maxAccumulator = new LongAccumulator(maxOperator, Long.MIN_VALUE);
// 3. 多线程并发输入值,统计最大值
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
int value = i 10; // 模拟输入值:0,10,20,...,90
executor.submit(() -> {
maxAccumulator.accumulate(value);
System.out.println(Thread.currentThread().getName() + " 输入值:" + value + ",当前最大值:" + maxAccumulator.get());
});
}
executor.shutdown();
executor.awaitTermination(1, java.util.concurrent.TimeUnit.MINUTES);
// 4. 最终最大值
System.out.println("最终最大值:" + maxAccumulator.get()); // 输出 90
}
}
运行结果
pool-1-thread-1 输入值:0,当前最大值:0
pool-1-thread-2 输入值:10,当前最大值:10
...
pool-1-thread-10 输入值:90,当前最大值:90
最终最大值:90
自定义“累加后取模”累加器
场景:多线程统计计数,且结果需限制在指定范围内(如模 100)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;
public class ModLongAccumulatorDemo {
public static void main(String[] args) throws InterruptedException {
// 1. 自定义累加规则:(已有值 + 输入值) % 100
LongBinaryOperator modOperator = (left, right) -> (left + right) % 100;
// 2. 初始值设为0
LongAccumulator modAccumulator = new LongAccumulator(modOperator, 0);
// 3. 多线程累加,每次加10,验证模100逻辑
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 15; i++) {
executor.submit(() -> {
modAccumulator.accumulate(10);
System.out.println(Thread.currentThread().getName() + " 累加后值:" + modAccumulator.get());
});
}
executor.shutdown();
executor.awaitTermination(1, java.util.concurrent.TimeUnit.MINUTES);
// 最终结果:1510=150 → 150%100=50
System.out.println("最终累加取模结果:" + modAccumulator.get()); // 输出 50
}
}
自定义“乘法”累加器
场景:多线程计算乘积(如批量计算因子的乘积)。
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;
public class MultiplyLongAccumulatorDemo {
public static void main(String[] args) {
// 1. 自定义累加规则:left(已有值) right(输入值)
LongBinaryOperator multiplyOperator = (left, right) -> left right;
// 2. 初始值设为1(乘法的单位元,确保第一个值不被0覆盖)
LongAccumulator multiplyAccumulator = new LongAccumulator(multiplyOperator, 1);
// 3. 依次输入因子:2345
multiplyAccumulator.accumulate(2); // 12=2
multiplyAccumulator.accumulate(3); // 23=6
multiplyAccumulator.accumulate(4); // 64=24
multiplyAccumulator.accumulate(5); // 245=120
System.out.println("乘积结果:" + multiplyAccumulator.get()); // 输出 120
}
}
LongAccumulator 高级用法:结合 Lambda 简化自定义逻辑
对于简单的自定义规则,可直接使用 Lambda 表达式简化代码,
无需显式声明 `LongBinaryOperator`:
import java.util.concurrent.atomic.LongAccumulator;
public class LongAccumulatorLambdaDemo {
public static void main(String[] args) {
// 1. 自定义“取最小值”累加器(Lambda 简化)
LongAccumulator minAccumulator = new LongAccumulator((left, right) -> Math.min(left, right), Long.MAX_VALUE);
minAccumulator.accumulate(50);
minAccumulator.accumulate(30);
minAccumulator.accumulate(40);
System.out.println("最小值:" + minAccumulator.get()); // 输出 30
// 2. 自定义“累加后平方”累加器
LongAccumulator squareAccumulator = new LongAccumulator((left, right) -> (left + right) (left + right), 0);
squareAccumulator.accumulate(2); // (0+2)²=4
squareAccumulator.accumulate(3); // (4+3)²=49
System.out.println("累加平方结果:" + squareAccumulator.get()); // 输出 49
}
}
LongAccumulator注意事项
1. 初始值的选择:
- 累加/乘法:初始值选“单位元”(累加选 0,乘法选 1);
- 最大值/最小值:初始值选极值(最大值选 `Long.MIN_VALUE`,最小值选 `Long.MAX_VALUE`),
确保第一个输入值能覆盖初始值。
2. 线程安全的核心:
`accumulate()` 方法是原子操作,但 `get()` 方法返回的是“近似值”(高并发下可能未汇总所有分段变量),
若需精确值,可调用 `longValue()` 或 `getThenReset()`(获取后重置)。
3. 性能优势场景:
高并发(线程数 > CPU 核心数)下,`LongAccumulator` 的分段累加机制性能远超 `AtomicLong`;
低并发场景下,二者性能差异不大。
4. 不可变的累加规则:
累加规则(`LongBinaryOperator`)在创建 `LongAccumulator` 时确定,后续无法修改,
若需动态调整规则,需重新创建实例。
5. 与 LongAdder 的关系:
`LongAdder` 是 `LongAccumulator` 的特例(累加规则固定为 `left + right`),
自定义逻辑优先选 `LongAccumulator`,简单累加可选 `LongAdder`。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。


