@TOC
- 在Atomic原子类-1 和 Atomic原子类-2
- 我们介绍了Atomic 的用法以及简单的底层实现,那么我们这片文章讲下Atomic 的累加器
Adder 累加器
- 是jdk 1.8 中引入的,比较新的一个类
- 高并发的情况下 LongAdder 比 AtomitLong 效率高,不过是空间换时间
- 竞争激烈的时候,LongAdder把不同的线程对应到不同的cell上进行修改,降低了冲突的概率,是多段锁的理念,提高了并发性
测试 AtomicLong的 性能
package com.yxzapp.ready;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
/**
* 演示高并发情况下LongAdder 比 AtomicLong
* 性能好
*/
public class AtomicLongDemo {
public static void main(String[] args) throws InterruptedException {
AtomicLong atomicLong = new AtomicLong(0);
//线程池开始时间
long start = System.currentTimeMillis();
ExecutorService executorService = Executors.newFixedThreadPool(20);
for (int i = 0; i < 10000; i++) {
executorService.submit(new Task(atomicLong));
}
//表示线程池执行完毕
executorService.shutdown();
while (!executorService.isTerminated()){
}
long end = System.currentTimeMillis();
System.out.println(atomicLong.get());
System.out.println("耗时"+(end -start));
}
public static class Task implements Runnable{
private AtomicLong atomicLong;
public Task(AtomicLong atomicLong) {
this.atomicLong = atomicLong;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
atomicLong.incrementAndGet();
}
}
}
}
运行结果:
package com.yxzapp.ready;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
/**
* 演示高并发情况下LongAdder 比 AtomicLong
* 性能好
*/
public class LongAdderDemo {
public static void main(String[] args) throws InterruptedException {
LongAdder atomicLong = new LongAdder();
//线程池开始时间
long start = System.currentTimeMillis();
ExecutorService executorService = Executors.newFixedThreadPool(20);
for (int i = 0; i < 10000; i++) {
executorService.submit(new Task(atomicLong));
}
//表示线程池执行完毕
executorService.shutdown();
while (!executorService.isTerminated()){
}
long end = System.currentTimeMillis();
System.out.println(atomicLong.sum() );
System.out.println("耗时"+(end -start));
}
public static class Task implements Runnable{
private LongAdder longAdder;
public Task(LongAdder longAdder) {
this.longAdder = longAdder;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
longAdder.increment();
}
}
}
}
在这里插入代码片
运行结果
会发现Longadder 比 AtomicLong 快了好多
- 他们内部实现有些不同,AtomicLong每次加法都需要同步,所以冲突的比较多,也就降低了效率
- 而 Longadder,每个线程都有自己的计数器,仅用来线程内计数,不会和其他线程干扰
- AtomicLong引入了分段锁的概念,内部有一个base变量 和 cell[] 数组共同参与计数
- base变量:竞争不激烈,直接累加到该变量上
- cell [] 数组: 竞争激烈,各个线程分累加到自己到cell[i] 卡槽中
Accumulator 累加器
- Accumualtor 和 Adder 非常相似,Accumualtor就是更通用的版本Adder
package com.yxzapp.ready;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.stream.IntStream;
public class LongAccumulatorDemo {
public static void main(String[] args) {
LongAccumulator accumulator = new LongAccumulator((x,y)->x+y,0);
ExecutorService executorService = Executors.newFixedThreadPool(8);
IntStream.range(1,10).forEach(i->executorService.submit(()->accumulator.accumulate(i)));
executorService.shutdown();
while (!executorService.isTerminated())
System.out.println(accumulator.getThenReset());
}
public class Task{
private LongAccumulator accumulator;
public Task(LongAccumulator accumulator) {
this.accumulator = accumulator;
}
}
}
对比: