阿里巴巴Java开发手册推荐使用LongAdder,为什么呢?

问题背景

17. 【参考】 volatile 解决多线程内存不可见问题对于一写多读,是可以解决变量同步问题,但是如果多
写,同样无法解决线程安全问题。
说明: 如果是 count++操作,使用如下类实现:
AtomicInteger count = new AtomicInteger();
count. addAndGet (1);
如果是 JDK8,推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)
推荐使用 LongAdder 对象,比 AtomicLong 性能更好(减少乐观锁的重试次数)

——引自阿里巴巴Java开发手册(黄山版)

真的吗?我们来测试一下

高并发情况下各种累加器性能测试,包括synchronized、AtomicInteger、AtomicLong、LongAdder、LongAccumulator

测试场景

10个线程,每个线程累加一千万次

测试代码


import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.concurrent.atomic.LongAdder;


class ClickNumber {

    int number = 0;

    public synchronized void add_synchronized() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();
    public void add_atomicInteger() {

        atomicInteger.incrementAndGet();
    }


    AtomicLong atomicLong = new AtomicLong();
    public void add_atomicLong() {
        atomicLong.incrementAndGet();
    }

    LongAdder longAdder = new LongAdder();
    public void add_longAdder() {
        longAdder.increment();
    }

    LongAccumulator accumulator = new LongAccumulator(((left, right) -> left + right), 0);
    public void add_accumulator() {

        accumulator.accumulate(1);
    }
}


public class TestJUC {

    public static final int THREAD_NUM = 10;
    public static final int THREAD_RUN_TIME = 10000000;

    public static void main(String[] args) throws InterruptedException {


        ClickNumber clickNumber = new ClickNumber();
        long start;
        long end;
        start = System.currentTimeMillis();
        CountDownLatch latch1 = new CountDownLatch(THREAD_NUM);
        CountDownLatch latch2 = new CountDownLatch(THREAD_NUM);
        CountDownLatch latch3 = new CountDownLatch(THREAD_NUM);
        CountDownLatch latch4 = new CountDownLatch(THREAD_NUM);
        CountDownLatch latch5 = new CountDownLatch(THREAD_NUM);
        for (int i = 0; i < THREAD_NUM; i++) {


            new Thread(() -> {
                try {
                    for (int j = 0; j < THREAD_RUN_TIME; j++) {
                        clickNumber.add_synchronized();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch1.countDown();
                }
            }, String.valueOf(i)).start();
        }

        latch1.await();

        end = System.currentTimeMillis();


        System.out.println("\n=========================\n");


        System.out.println("add_synchronized耗时 "+(end - start)+" 结果为 "+clickNumber.number);
        System.out.println("\n=========================\n");


        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUM; i++) {


            new Thread(() -> {
                try {
                    for (int j = 0; j < THREAD_RUN_TIME; j++) {
                        clickNumber.add_atomicInteger();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch2.countDown();
                }
            }, String.valueOf(i)).start();
        }

        latch2.await();

        end = System.currentTimeMillis();

        System.out.println("add_atomicInteger耗时 "+(end - start)+" 结果为 "+clickNumber.atomicInteger.get());


        System.out.println("\n=========================\n");


        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUM; i++) {


            new Thread(() -> {
                try {
                    for (int j = 0; j < THREAD_RUN_TIME; j++) {
                        clickNumber.add_atomicLong();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch3.countDown();
                }
            }, String.valueOf(i)).start();
        }

        latch3.await();

        end = System.currentTimeMillis();

        System.out.println("add_atomicLong耗时 "+(end - start)+" 结果为 "+clickNumber.atomicLong.get());


        System.out.println("\n=========================\n");


        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUM; i++) {


            new Thread(() -> {
                try {
                    for (int j = 0; j < THREAD_RUN_TIME; j++) {
                        clickNumber.add_longAdder();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch4.countDown();
                }
            }, String.valueOf(i)).start();
        }

        latch4.await();

        end = System.currentTimeMillis();

        System.out.println("add_longAdder耗时 "+(end - start)+" 结果为 "+clickNumber.longAdder.longValue());



        System.out.println("\n=========================\n");


        start = System.currentTimeMillis();
        for (int i = 0; i < THREAD_NUM; i++) {


            new Thread(() -> {
                try {
                    for (int j = 0; j < THREAD_RUN_TIME; j++) {
                        clickNumber.add_accumulator();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    latch5.countDown();
                }
            }, String.valueOf(i)).start();
        }

        latch5.await();

        end = System.currentTimeMillis();

        System.out.println("add_accumulator耗时 "+(end - start)+" 结果为 "+clickNumber.accumulator.longValue());

    }

测试结果

=========================

add_synchronized耗时 6922 结果为 100000000

=========================

add_atomicInteger耗时 1239 结果为 100000000

=========================

add_atomicLong耗时 1150 结果为 100000000

=========================

add_longAdder耗时 288 结果为 100000000

=========================

add_accumulator耗时 305 结果为 100000000

总结

LongAdder真香
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值