我看到Java的AtomicInteger如何在内部使用CAS(比较和交换)操作.基本上,当多个线程尝试更新值时,JVM在内部使用底层CAS机制并尝试更新该值.如果更新失败,则再次尝试使用新值但从不阻止.
在Java8中,Oracle引入了一个新的类LongAdder,它在高争用下似乎比AtomicInteger表现更好.一些博客文章声称LongAdder通过维护内部单元格表现更好 - 这是否意味着LongAdder在内部聚合值并在以后更新它?你能帮我理解LongAdder的工作原理吗?
这是否意味着LongAdder在内部聚合值并在以后更新?
是的,如果我理解你的陈述.
Cella LongAdder中的每个都是a的变体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();
Run Code Online (Sandbox Code Playgroud)
小智 7
它“更快”的主要原因是其有竞争力的性能。这很重要,因为:
在低更新争用下,这两个类具有相似的特征。
您将使用 LongAdder 进行非常频繁的更新,其中原子 CAS 和本机调用Unsafe会导致争用。(见源和挥发性读取)。更不用说多个 AtomicLongs 上的缓存未命中/错误共享(虽然我还没有查看类布局,但在实际long字段之前似乎没有足够的内存填充。
在高争用情况下,此类的预期吞吐量显着更高,但代价是更高的空间消耗。
实现 extends Striped64,它是 64 位值的数据持有者。这些值保存在单元格中,这些单元格被填充(或条纹),因此得名。对 LongAdder 进行的每个操作都将修改 Striped64 中存在的值集合。当发生争用时,会创建并修改一个新单元,因此旧线程可以与争用线程同时完成。当您需要最终值时,只需将每个单元格的总和相加即可。
不幸的是,性能是有代价的,在这种情况下是内存(通常是这样)。如果大量线程和更新被抛出,Striped64 会变得非常大。
引用来源: LongAdder 的 Javadoc
| 归档时间: |
|
| 查看次数: |
7108 次 |
| 最近记录: |