【小家java】AtomicLong可以抛弃了,请使用LongAdder代替(或使用LongAccumulator)(下)

简介: 【小家java】AtomicLong可以抛弃了,请使用LongAdder代替(或使用LongAccumulator)(下)

LongAdder和AtomicLong性能对比测试


说了这么多,出现LongAdder就是为了来提高并发性能的,那么是骡子是马,拉出来遛遛吧:


    //访问的线程总数
    public static final int THREAD_COUNT = 100;
    //循环的总次数
    public static final int LOOP_COUNT = 10000;
    static ExecutorService pool = Executors.newFixedThreadPool(THREAD_COUNT);
    static CompletionService<Long> completionService = new ExecutorCompletionService<>(pool);
    //static的共享变量
    static final AtomicLong atomicLong = new AtomicLong(0L);
    static final LongAdder longAdder = new LongAdder();
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_COUNT; i++) {
            completionService.submit(() -> {
                for (int j = 0; j < 100000; j++) {
                    //对比只需要求欢此方法即可
                    atomicLong.incrementAndGet();
                    //longAdder.increment();
                }
                return 1L;
            });
        }
        for (int i = 0; i < THREAD_COUNT; i++) {
            Future<Long> future = completionService.take();
            future.get();
        }
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        pool.shutdown();
    }


第一把:线程100个,循环总次数10000次:


LongAdder耗时:300ms
AtomicLong耗时:265ms


第二把:线程100个,循环总次数100000次:


LongAdder耗时:306ms
AtomicLong耗时:439ms


第三把:线程1000个,循环总次数10000次:


LongAdder耗时:613ms
AtomicLong耗时:735ms


第四把:线程1000个,循环总次数1000000次:


LongAdder耗时:5463ms
AtomicLong耗时:37964ms


从上面的性能测试,可以得出结论:


在并发比较低的时候,LongAdder和AtomicLong的效果非常接近

但是当并发较高时,两者的差距会越来越大。如上最后一个,当并发大循环次数多的时候,LongAdder的优势非常明显(6倍以上)


LongAccumulator


关于LongAccumulator,可以说是加强版的LongAdder。LongAdder的API相对比较简陋,只有对数值的加减,而LongAccumulator提供了自定义的函数操作,我们可以自己去决定计算方式。

    // accumulatorFunction:需要执行的二元函数(接收2个long作为形参,并返回1个long);identity:初始值
    public LongAccumulator(LongBinaryOperator accumulatorFunction, long identity) {
        this.function = accumulatorFunction;
        base = this.identity = identity;
    }


accumulatorFunction:需要执行的二元函数(接收2个long作为形参,并返回1个long);

identity:初始值。下面看一个Demo:


代码示例:

    public static void main(String[] args) throws InterruptedException {
        //这样就可以很安全的求和操作了
        LongAccumulator accumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);
        Thread[] ts = new Thread[1000];
        for (int i = 0; i < 1000; i++) {
            ts[i] = new Thread(() -> {
                Random random = new Random();
                long value = random.nextLong();
                accumulator.accumulate(value); // 比较value和上一次的比较值,然后存储较大者
            });
            ts[i].start();
        }
        for (int i = 0; i < 1000; i++) {
            ts[i].join();
        }
        System.out.println(accumulator.longValue()); //9207653574451187103
    }


accumulate(value)传入的值会与上一次的比较值对比,然后保留较大者,最后打印出最大值。


LongAdder可以代替AtomicLong吗?


话有说回来啊,JDK8并没有把AtomicLong标记为过期,所以肯定还是很多用武之地的。

从LongAdder的Api可以看出,提供的方法还是挺少的。它更多地用于收集统计数据,而不是细粒度的同步控制。

LongAdder只提供了add(long)和decrement()方法,想要使用CAS更全面的方法还是要选择AtomicLong。

因此如果你只需要做形如count++的操作,推荐使用LongAdder代替AtomicLong吧(阿里开发手册就是这么推荐的)


DoubleAdder和DoubleAccumulator使用方法类似,这里不在介绍


注意,没有提供IntegerAdder哦~

相关文章
|
Java p3c
【Java用法】请使用System.currentTimeMillis()代替new Date().getTime()
【Java用法】请使用System.currentTimeMillis()代替new Date().getTime()
259 0
|
安全 Java 测试技术
解密Java并发中的秘密武器:LongAdder与Atomic类型
解密Java并发中的秘密武器:LongAdder与Atomic类型
496 1
|
算法 Java 容器
深入解析Java并发库(JUC)中的LongAdder
深入解析Java并发库(JUC)中的LongAdder
|
存储 安全 Java
4.2 Java数组性能优化策略:使用ArrayList代替原生数组
4.2 Java数组性能优化策略:使用ArrayList代替原生数组
511 0
|
缓存 算法 安全
Java Review - 并发编程_原子操作类LongAdder & LongAccumulator剖析
Java Review - 并发编程_原子操作类LongAdder & LongAccumulator剖析
249 0
|
缓存 Java API
Java8原子弹类之LongAdder源码分析
JDK 8开始,针对Long型的原子操作, Java又提供了LongAdder. LongAccumulator; 针对Double类型,Java提供了DoubleAdder、DoubleAccumulator。
157 0
Effective Java--第1条静态工厂方法代替构造方法
Effective Java--第1条静态工厂方法代替构造方法
176 0
Effective Java--第1条静态工厂方法代替构造方法
|
安全 IDE JavaScript
为什么要用Kotlin代替Java
为什么要用Kotlin代替Java
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
125 0