Java8 教程

Java LongAccumulator 和 DoubleAccumulator 类

前面介绍了使用 LongAdder DoubleAdder 来实现 Long 和 Double 类型数据在多线程下安全的、高性能的累加。除了这两个工具类,Java8 还引入了 LongAccumulator DoubleAccumulator 类,提供了比 LongAdder 和 DoubleAdder 类更强大、更灵活的功能,允许你自定义累加规则,并可以为累加器设置非零的初始值。

LongAccumulator 类

LongAccumulator 类是一个线程安全的类,用于在高并发环境下执行自定义的 long 类型数值累加操作。

LongAccumulator 和 LongAdder 实现原理类似,内部维护了一个或多个 Cell 对象,用于存储累加的值。每个线程在更新时,会尝试将其值累加到某个 Cell 上,从而减少了全局锁的竞争,提高了并发性能。

构造方法

LongAccumulator 类提供了一个构造方法,该方法接受两个参数,定义如下:

LongAccumulator(LongBinaryOperator accumulatorFunction, long identity)

参数说明:

  • LongBinaryOperator accumulatorFunction:这是一个函数式接口的实现,定义了累加操作的规则。它接受两个 long 类型的参数,并返回一个 long 类型的结果。定义如下:

long applyAsLong(long left, long right)
  • long identity:这是累加器的初始值。

主要方法

LongAccumulator 主要提供如下函数:

  • accumulate(long x):将给定的值 x 累加到累加器中。具体的累加规则由构造函数中传入的accumulatorFunction 定义。

  • get():返回累加器的当前值。这是一个最终一致性操作,即它返回的是累加器在某一时间点的近似值,而不是实时值。

  • reset():将累加器的值重置为初始值(由构造函数中的identity参数指定)。

简单示例

假设我们创建一个线程池 executorService,然后创建 10 个线程,每个线程对 LongAccumulator 累加一个数字。LongAccumulator 的初始值为 5。 如下:

package com.hxstrive.jdk8.concurrent.atomic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;

/**
 * LongAccumulator 类
 * @author HuangXin
 * @since 1.0.0  2024/7/9 13:14
 */
public class LongAccumulatorDemo1 {

    public static void main(String[] args) {
        // 创建线程池
        final ExecutorService executorService = Executors.newFixedThreadPool(10);
        final LongAccumulator longAccumulator = new LongAccumulator(Long::sum, 5);

        for(int i = 0; i < 10; i++) {
            final int index = (i + 1) * 100;
            executorService.submit(() -> longAccumulator.accumulate(index));
        }

        executorService.shutdown();
        while(!executorService.isTerminated()) {}
        System.out.println("value=" + longAccumulator.get()); //value=5505
    }

}

Java8 中除了 LongAccumulator 类以外,还提供了 DoubleAccumulator 类。

DoubleAccumulator 类

DoubleAccumulator 类是 Java 并发编程库中的一个工具类,它用于多线程环境下对 double 类型数值进行安全地累加。工作方式和 LongAccumulator 基本类似,不过是用于 double 类型的值。

构造方法

DoubleAccumulator类提供了一个构造方法,该方法接受两个参数:

DoubleAccumulator(DoubleBinaryOperator accumulatorFunction, double identity)

参数说明:

  • DoubleBinaryOperator accumulatorFunction:这是一个函数式接口的实现,定义了累加操作的规则。它接受两个 double 类型的参数,并返回一个 double 类型的结果。定义如下:

double	applyAsDouble(double left, double right)
  • double identity:这是累加器的初始值。

主要方法

  • accumulate(double x):将给定的值x累加到累加器中。具体的累加规则由构造函数中传入的accumulatorFunction定义。

  • get():返回累加器的当前值。这是一个最终一致性操作,即它返回的是累加器在某一时间点的近似值,而不是实时值。

  • reset():将累加器的值重置为初始值(由构造函数中的 identity 参数指定)。

  • doubleValue():与 get() 等价。

  • floatValue():以浮点形式返回当前值。

  • getThenReset():相当于调用 get() 之后,调用 reset()。

  • intValue():以 int 返回当前值。

  • longValue():以 long 形式返回当前值。

简单示例

假设我们创建一个线程池 executorService,然后创建 10 个线程,每个线程对 DoubleAccumulator 累加一个数字。DoubleAccumulator 的初始值为 5。 如下:

package com.hxstrive.jdk8.concurrent.atomic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.DoubleAccumulator;
import java.util.concurrent.atomic.LongAccumulator;

/**
 * DoubleAccumulator 类
 * @author hxstrive.com
 */
public class DoubleAccumulatorDemo1 {

    public static void main(String[] args) {
        // 创建线程池
        final ExecutorService executorService = Executors.newFixedThreadPool(10);
        // 设置基础值为 5
        final DoubleAccumulator doubleAccumulator = new DoubleAccumulator(Double::sum, 5);

        for(int i = 0; i < 10; i++) {
            final int index = (i + 1) * 100;
            executorService.submit(() -> doubleAccumulator.accumulate(index));
        }

        executorService.shutdown();
        while(!executorService.isTerminated()) {}
        System.out.println("value=" + doubleAccumulator.get()); //value=5505.0
        System.out.println("value=" + doubleAccumulator.longValue()); //value=5505
    }

}
说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号