How LongAdder performs better than AtomicLong
我看到Java的AtomicInteger如何在内部使用CAS(比较和交换)操作。 基本上,当多个线程尝试更新值时,JVM在内部使用底层CAS机制并尝试更新该值。 如果更新失败,则再次尝试使用新值但从不阻止。
在Java8中,Oracle引入了一个新的类LongAdder,它在高争用下似乎比AtomicInteger表现更好。 一些博客文章声称LongAdder通过维护内部单元格表现更好 - 这是否意味着LongAdder在内部聚合值并在以后更新? 你能帮我理解LongAdder的工作原理吗?
does that mean LongAdder aggregates the values internally and update it later?
是的,如果我理解你的陈述。
当要检索最终结果(总和)时,它只是将每个单元格的值加在一起。
关于如何组织单元格,如何分配单元格等的大部分逻辑可以在源代码中看到:http://hg.openjdk.java.net/jdk9/jdk9/jdk/file/f398670f3da7/src/java.base /share/classes/java/util/concurrent/atomic/Striped64.java
特别是单元的数量受CPU数量的限制:
1 2 | /** Number of CPUS, to place bound on table size */ static final int NCPU = Runtime.getRuntime().availableProcessors(); |
"更快"的主要原因是它的竞争性能。这很重要,因为:
Under low update contention, the two classes have similar characteristics.
您将使用LongAdder进行非常频繁的更新,其中原子CAS和对
under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.
实现扩展
不幸的是,性能带来了成本,在这种情况下是内存(通常是这样)。如果向它抛出大量线程和更新,Striped64可能会变得非常大。
报价来源:
Javadoc for LongAdder
Atomic Long使用CAS,在严重争用下会导致许多浪费的CPU周期。
另一方面,LongAdder使用一种非常聪明的技巧来减少线程之间的争用,当它们递增时。
因此,当我们调用
因此,当更多线程调用increment()时,数组将更长。阵列中的每条记录都可以单独更新 - 减少争用。由于这个事实,LongAdder是一种从多个线程递增计数器的非常有效的方法。
在我们调用