JDK8原子操作类——LongAdder

与AtomicLong有什么区别?

AtomicLong通过CAS操作提供非阻塞的原子操作,但是CAS失败是通过无限循环的自旋锁不断尝试的。

int prev, next;
do {
    ...
} while (!compareAndSet(prev, next));

在高并发条件下,同时去操作一个变量会造成大量线程CAS失败然后处于自旋状态,这大大浪费了cpu资源,降低了并发性。LongAdder根据把一个变量分解为多个变量,让同样多的线程去竞争多个资源,可以解决Atomic带来的资源浪费问题。LongAdder解决失败的问题不是CAS循环重试,而是尝试获取其他原子变量的锁,最后获取当前值时候是把所有变量的值累加后返回。

一个延迟初始化的原子性更新数组transient volatile Cell[] cells和一个基值变量transient volatile long base数组的大小保持是2的N次方大小,数组表的下标使用每个线程的hashcode值的掩码表示,数组里面的变量实体是Cell类型Cell类型是AtomicLong的一个改进,用来减少缓存的争用。由于Cell占用内存空间比较大,所以是惰性加载。当一开始没有空间时候,所有的更新都是操作base变量。

transient volatile int cellsBusy 初始化和扩容数组表使用。当一次线程发现当前下标的元素获取锁失败后,会尝试获取其他下表的元素的锁,最后获取当前值时候是把所有变量的值累加后返回。累加过程中并没有使用锁,所以在计算返回值时候可能某些元素的值已经被修改了,但是返回值是一个快照值,保证了弱一致性