java.util.concurrent.atomic.longadder类的可行性

xcitsw88  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(491)

LongAdder 是一个巧妙设计的原子计数器,它应该在更新共享计数器时减少缓存线争用。问题是,它依赖于原子cas操作来实际更新计数(这是它与更通用的 LongAccumulator 和朋友)。
在amd64平台上(可能在其他地方),原子cas比原子add慢得多,至少在涉及到中等数量的核时是这样。因此,看起来,简单地对一个共享的 VarHandle 是一个更好的主意:代码更简单,而在一个普通的(大约8核)容器上,性能不会更差甚至更好。
正在使用 LongAdder 与…相比有什么好处 VarHandle 中介原子加法?
想了解更多情况:
默认情况下,java以cas循环的形式执行所有原子操作(甚至是简单的算术运算)(例如:https://github.com/openjdk/jdk/blob/64644a10725abb4bea8a947508999be6c67c52ed/src/java.base/share/classes/jdk/internal/misc/unsafe.java#l2468). 如果jit愿意的话,它可以自由地将内部函数升级到更好的东西。 LongAdder ,作为一个分片cas循环,肯定比任何简单的cas循环都快,即使在低争用级别上也是如此。
然而,似乎“每个cpu一个cas碎片”场景( LongAdder 对于任何争用级别,都比amd64上的实际硬件原子加法(“lock xadd”指令)慢一些。通过大幅度增加碎片的数量(至少2倍的cpu数量,在大的倍数(如8倍或更高)上可以实现额外的增益),可以加快速度。
不过,对一个适当的原子计数器进行简单的切分(即用硬件加法代替cas的计数器)仍然会更快、更简单。

ztmd8pv5

ztmd8pv51#

LongAdder 设计用于在写容量大的场景中更好地扩展,而不是 AtomicLong 在任何争论的层次上,除了没有,确实是这样。
如果你的场景不是写得很重,那么 AtomicLong 会更快。
c2编译器总是替换 @HotSpotIntrinsicCandidate -带有硬编码程序集的带注解的方法,而不仅仅是在感觉这样做的时候。 lock xadd 比cas retry循环增加值快。 LongAdder 比…快 lock xadd ,因为它在线程之间拆分计数器。它创建多个计数器,因此减少了争用。

相关问题