Java 比Automic更高效的累加器

1、 java常见的原子类

类 Atomiclnteger、AtomicIntegerArray、AtomicIntegerFieldUpdater、AtomicLongArray、 AtomicLongFieldUpdater、AtomicReference、AtomicReferenceArray 和 AtomicReference- FieldUpdater

常见的原子类使用方法

使用 AtomicReference 来创建一个原子的 Double 引用 atomicDouble,初始值为 0.0。然后,多个线程并发执行累加操作,在每个线程内部使用 compareAndSet 方法来原子地更新累加结果。

compareAndSet 方法是 AtomicReference 类的原子操作方法,它会比较当前值是否与期望值相等,如果相等,则更新为新的值。如果当前值与期望值不相等,那么更新操作失败,线程需要重试。

请注意,使用 AtomicReference 只是一种手段,实现了类似原子操作的效果。由于 Double 是一个包装类型,操作它的时候需要注意自动装箱和拆箱的性能开销。如果需要高性能的原子 double 操作,可以考虑使用类似 DoubleAdder 的高性能原子类。

代码:

import java.util.concurrent.atomic.AtomicReference;

public class AtomicDoubleExample {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        AtomicReference<Double> atomicDouble = new AtomicReference<>(0.0);

        // 多个线程并发执行累加操作
        for (int i = 1; i <= 10; i++) {
    
    
            final double valueToAdd = i * 1.0; // 值为 1.0, 2.0, 3.0, ..., 10.0
            new Thread(() -> {
    
    
                while (true) {
    
    
                    Double oldValue = atomicDouble.get();
                    Double newValue = oldValue + valueToAdd;
                    if (atomicDouble.compareAndSet(oldValue, newValue)) {
    
    
                        // 成功更新后退出循环
                        break;
                    }
                }
            }).start();
        }

        // 主线程等待所有累加线程执行完成
        Thread.sleep(1000);

        // 打印累加结果
        System.out.println("Accumulated Result: " + atomicDouble.get());
    }
}

2、更高效的累加器Adder、Accumulator

例如:DoubleAdder和DoubleAccumulator也是用来处理double类型的值,并且在处理方式上与LongAdder和LongAccumulator类似

DoubleAdder

DoubleAdder是用于高效处理double类型累加操作的类。与AtomicLong相比,DoubleAdder在高并发环境下能够提供更好的性能,因为它采用了分散(Striped)的设计,将内部的数据分为多个独立的单元进行累加,减少了竞争,从而提高了吞吐量。

DoubleAdder的常用方法包括:

add(double x): 将指定的double值加到当前总和。
sum(): 返回当前的总和值。

示例代码:


public class CustomDoubleAdder {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
     DoubleAdder doubleAdder = new DoubleAdder();

// 多个线程并发执行累加操作
for (int i = 0; i < 10; i++) {
    
    
    new Thread(() -> {
    
    
        doubleAdder.add(1.0);
    }).start();
}

// 主线程等待所有累加线程执行完成
Thread.sleep(1000);

System.out.println("Sum: " + doubleAdder.sum());
 }
}

DoubleAccumulator

DoubleAccumulator也用于高效处理double类型的累加操作,不同的是它可以自定义累加的逻辑。DoubleAccumulator使用DoubleBinaryOperator函数接口来定义累加操作的逻辑。

DoubleAccumulator的常用方法包括:

accumulate(double x): 使用自定义的累加函数将指定的double值加到当前累加结果。
get(): 返回当前的累加结果。

示例代码:
使用 DoubleBinaryOperator 函数接口来定义自定义的累加逻辑。DoubleBinaryOperator 是一个函数接口,它接受两个 double 类型的参数,并返回一个 double 类型的结果。使用 lambda 表达式或实现该接口来定义累加逻辑。

构造 DoubleAccumulator 时,需要传递一个初始值和一个 DoubleBinaryOperator 对象。初始值是累加的起始值,而 DoubleBinaryOperator 对象定义了每次累加时的操作逻辑。

import java.util.concurrent.atomic.DoubleAccumulator;
import java.util.function.DoubleBinaryOperator;

public class CustomDoubleAccumulator {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        // 定义自定义的累加逻辑,这里使用乘法进行累加
        DoubleBinaryOperator customAccumulator = (x, y) -> x * y;

        // 初始值为1.0
        double initialValue = 1.0;
        DoubleAccumulator doubleAccumulator = new DoubleAccumulator(customAccumulator, initialValue);

        // 多个线程并发执行累加操作
        for (int i = 1; i <= 10; i++) {
    
    
            final double valueToAdd = i * 1.0; // 值为 1.0, 2.0, 3.0, ..., 10.0
            new Thread(() -> {
    
    
                doubleAccumulator.accumulate(valueToAdd);
            }).start();
        }

        // 主线程等待所有累加线程执行完成
        Thread.sleep(1000);

        // 打印累加结果
        System.out.println("Accumulated Result: " + doubleAccumulator.get());
    }
}

猜你喜欢

转载自blog.csdn.net/FLGBgo/article/details/132102875