0
点赞
收藏
分享

微信扫一扫

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

JakietYu 2022-06-24 阅读 94

问题背景



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真香

举报

相关推荐

阿里巴巴Java开发手册

0 条评论