版权声明:本文为博主原创文章,转载请注明出处:http://blog.jerkybible.com/2018/01/11/Java并发源码之LongAdder/
访问原文「Java并发源码之LongAdder」
前言
AtomicLong
我已经在之前的文章Java并发源码之AtomicLong中做了详细的介绍。但是除了AtomicLong
,还存在另外一个高效的并发计数类,那就是LongAdder
。LongAdder
官方文档的说明如下。我就不对这段文字做详细的说明了,简单来说,这个类用于在多线程情况下的求和。
从关键方法分析
下面将从LongAdder
的关键方法add
来解析这个类。首先我把这个方法列出来,如下。
add
方法包含了一个Cell
数组,Cell
是Striped64的一个内部类。它的定义为:Padded variant of AtomicLong supporting only raw accesses plus CAS,翻译一下就是AtomicLong的填充变体并且只支持原始访问和CAS。下面列出了它的实现,可以看到Cell
有一个value变量,并且提供了一个cas方法更新value值。
接下来看第一个if语句,这句首先判断cells是否还没被初始化,并且尝试对value值进行cas操作。如果cells已经初始化并且cas操作失败,则运行if内部的语句。在进入第一个if语句之后紧接着是另外一个if,这个if有4个判断:cell[]数组是否初始化;cell[]数组虽然初始化了但是数组长度是否为0;该线程所对应的cell是否为null;尝试对该线程对应的cell单元进行cas更新是否失败,如果这些条件有一条为true,则运行最为核心的方法longAccumulate
,下面列出这个方法,为了便于理解,直接将对其的分析写为注释。
从以上分析来看,longAccumulate
就是为了尽量减少多个线程更新同一个值value,最后实在不行则采用扩大cell的方式。
可以看到,LongAdder
减少冲突的方法以及在求和场景下比AtomicLong更高效。原因是LongAdder
在更新数值的时候并不是对一个数进行更新,而是分散到多个cell,这样在多线程的情况下可以有效的嫌少冲突和压力,使得更加高效。
LongAdder的使用场景
LongAdder
适用于统计求和计数的场景,因为它提供了add
、sum
方法。
LongAdder是否能够替换AtomicLong
从上面的分析来看是不行的,因为AtomicLong
提供了很多cas方法,例如getAndIncrement
、getAndDecrement
等,使用起来非常的灵活,而LongAdder
只有add
和sum
,使用起来比较受限。