Java 原子类LongAccumulator自定义累加器

Java教程 发布时间:2025-12-26 17:38:10 阅读数:4301 1
下文笔者讲述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`。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaCourse/202512/8531.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者