赞
踩
多个线程更新用于收集统计信息而不是细粒度同步控制的公共和时,LongAdder通常比AtomicLong更可取。在低级别争用下,这两个类具有相似的特性。但在高争用情况下,LongAdder的预期吞吐量明显更高,这是以更高的空间消耗为代价的。
AtomicLong内部直接使用CAS完成原子化加算:
public final long getAndAdd(long delta) {
return unsafe.getAndAddLong(this, valueOffset, delta);
}
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));
return var6;
}
这种方式在低并发的情况下不会自旋太多次就能成功,损失有限,但是随着并发量的提升,CAS失败导致的自旋次数会急剧上升,这会导致AtomicLong的效率急剧下降,大量的自旋也会导致CPU的严重浪费。这种方式的根本原因就是因为多个线程争抢一个资源导致的,LongAdder对此做出了优化,将一个变量拆分成多个变量:
LongAdder并不是一开始就进行遍历拆分,最初他会和AtomicLong一样,维护一个变量进行CAS加算,只有出现并发导致CAS失败时才会进行拆分。
cell初始有两个,后续会根据争用情况进行二倍扩容。这是拆分资源的方式能大大提升高并发时的处理效率,缺点是需要更多的内存空间,是一种以空间换时间的方式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。