LongAdder只能用来计算加法,且从零开始计算
LongAccumulator提供了自定义的操作函数
普通int+sychronized、AtomicInteger和LongAdder的性能比较
public class LongAdderCalcDemo {
int num = 0;
public synchronized void add_synchronized() {
num++;
}
AtomicInteger atomicInteger = new AtomicInteger();
public void add_AtomicInteger() {
atomicInteger.incrementAndGet();
}
LongAdder longAdder = new LongAdder();
public void add_LongAdder() {
longAdder.increment();
}
public static void main(String[] args) throws InterruptedException {
int count = 50;
int size = 1000000;
LongAdderCalcDemo demo = new LongAdderCalcDemo();
CountDownLatch countDownLatch1 = new CountDownLatch(count);
CountDownLatch countDownLatch2 = new CountDownLatch(count);
CountDownLatch countDownLatch3 = new CountDownLatch(count);
long start;
long end;
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Thread(()->{
try {
for (int j = 0; j < size; j++) {
demo.add_synchronized();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch1.countDown();
}
}).start();
}
countDownLatch1.await();
end = System.currentTimeMillis();
System.out.println("add_synchronized costTime = " + (end - start) + " 毫秒, 结果 = " + demo.num);
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Thread(()->{
try {
for (int j = 0; j < size; j++) {
demo.add_AtomicInteger();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch2.countDown();
}
}).start();
}
countDownLatch2.await();
end = System.currentTimeMillis();
System.out.println("add_AtomicInteger costTime = " + (end - start) + " 毫秒, 结果 = " + demo.atomicInteger.get());
start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Thread(()->{
try {
for (int j = 0; j < size; j++) {
demo.add_LongAdder();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch3.countDown();
}
}).start();
}
countDownLatch3.await();
end = System.currentTimeMillis();
System.out.println("add_LongAdder costTime = " + (end - start) + " 毫秒, 结果 = " + demo.longAdder.sum());
}
}
add_synchronized costTime = 1880 毫秒, 结果 = 50000000
add_AtomicInteger costTime = 1123 毫秒, 结果 = 50000000
add_LongAdder costTime = 115 毫秒, 结果 = 500000
原理
Striped64中有2个重要的属性,long base和Cell[] cells数组
Cell是Striped64的内部类
LongAdder在无竞争的情况下,跟AtomicLong一样,对同一个base进行操作,当出现竞争关系时采用化整为零的做法,用空间换时间,分散热点,将value值分散到一个cell数组中,不同线程会命中到数组中的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就被分散了,冲突的概率就小很多。如果要获取真正的long值,只要将各个槽中的变量值累加返回。
sum()会将所有cell数组中的value和base累加作为返回值,核心思想就是将之前AtomicLong一个value的更新压力分散到多个cell中去,从而降级更新热点。
longAdder.sum()返回当前值,在没有并发更新value的情况下,sum()会返回一个精确值,在存在并发的情况下,sum()不保证返回精确值。
sum()执行时,并没有限制对base和cells的更新,所以LongAdder不是强一致性,它是最终一致性的。