LongAdder
替代AtomicLong
ExecutorService executor = Executors.newFixedThreadPool(2);
IntStream.range(0, 1000)
.forEach(i -> executor.submit(adder::increment));
stop(executor);
System.out.println(adder.sumThenReset()); // => 1000
LongAccumulator
是LongAdder
LongBinaryOperator op = (x, y) -> 2 * x + y;
LongAccumulator accumulator = new LongAccumulator(op, 1L);
ExecutorService executor = Executors.newFixedThreadPool(2);
IntStream.range(0, 10)
.forEach(i -> executor.submit(() -> accumulator.accumulate(i)));
stop(executor);
System.out.println(accumulator.getThenReset()); // => 2539
我有一些疑问。
LongAdder
总是优先于AtomicLong吗?答案 0 :(得分:6)
Javadoc中提到了这些类之间的差异,以及何时使用其中一个类。来自LongAdder
:
当多个线程更新用于收集统计信息但不用于细粒度同步控制的目的的公共和时,此类通常优于
AtomicLong
。在低更新争用下,这两个类具有相似的特征。但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高。
当多个线程更新用于收集统计信息但不用于细粒度同步控制的目的的公共值时,此类通常优于
AtomicLong
。在低更新争用下,这两个类具有相似的特征。但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高。[...]
类
LongAdder
提供了此类功能的类比,用于维护计数和总和的常见特殊情况。致电new LongAdder()
相当于new LongAccumulator((x, y) -> x + y, 0L)
。
因此,使用一个而不是另一个取决于您的应用程序打算做什么。它并不总是严格优先考虑,只有在预期高并发并且您需要维持一个共同状态时才会优先考虑。
答案 1 :(得分:1)
添加到单元格需要每个线程一个单元格。内部代码使用Striped64中的getProbe()返回:
返回UNSAFE.getInt(Thread.currentThread(),PROBE);
Probe是threadLocalRandomSeed中使用的系统字段。
我的理解是探针对于每个线程都是唯一的。如果你有大量的线程创建/销毁,那么为每个新线程创建探针。
因此,细胞数量可能过多。如果有人有更详细的信息,我想听听你的意见。