LongAdder如何比AtomicLong更好地执行

我看到Java的AtomicInteger如何与CAS(比较和交换)操作内部协同工作。 基本上,当多线程尝试更新值时,JVM内部使用底层CAS机制并尝试更新值。 如果更新失败,则再次尝试使用新值但不会阻止。

在Java8中,Oracle引入了一个新的Class LongAdder,它在高争用情况下似乎比AtomicInteger更好。 一些博客文章声称LongAdder通过维护内部单元格表现更好 - 这是否意味着LongAdder在内部聚合值并在稍后更新? 你能否帮我理解LongAdder的工作原理?


这是否意味着LongAdder会在内部汇总这些值并在稍后进行更新?

是的,如果我正确理解你的陈述。

LongAdder中的每个Cell都是AtomicLong的变种。 拥有多个这样的小区是扩展竞争并从而增加吞吐量的一种方式。

当最终结果(总和)将被检索时,它只是将每个单元格的值加起来。

有关细胞如何组织,如何分配等的大部分逻辑可以在源代码中看到:http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/f398670f3da7/src/java.base /share/classes/java/util/concurrent/atomic/Striped64.java

特别是单元的数量受到CPU数量的限制:

/** Number of CPUS, to place bound on table size */
static final int NCPU = Runtime.getRuntime().availableProcessors();

“更快”的主要原因是其竞争性能。 这很重要,因为:

在低更新争用下,这两个类别具有相似的特征。

您将使用LongAdder进行非常频繁的更新,其中原子CAS和本地调用Unsafe会导致争用。 (请参阅源和易失性读取)。 更不要说在多个AtomicLong上缓存未命中/错误共享(虽然我还没有看过类布局,但在实际的long字段之前似乎没有足够的内存填充。

在高度争论中,该类别的预期吞吐量显着较高,但以空间消耗较高为代价。

该实现扩展了Striped64 ,它是64位值的数据持有者。 这些值保存在填充(或条纹)的单元格中,因此名称。 LongAdder可能会修改Striped64中存在的值的集合。 发生争用时,将创建并修改新的单元格,以便旧线程可以与争用的线程同时完成。 当你需要最终的价值时,每个细胞的总和简单地加起来。

不幸的是,性能带来了成本,在这种情况下是内存(经常是这样)。 如果大量的线程和更新被抛出,Striped64会变得非常大。

引用来源:LongAdder的Javadoc

链接地址: http://www.djcxy.com/p/92193.html

上一篇: How LongAdder performs better than AtomicLong

下一篇: Map alternative for primitive values