java 8:LongAdder和LongAccumulator是AtomicLong的首选吗?

时间:2016-02-28 22:03:43

标签: java concurrency java-8

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

LongAccumulatorLongAdder

的更通用版本
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

我有一些疑问。

  1. LongAdder总是优先于AtomicLong吗?
  2. 是否优先考虑LongAdder和AtomicLong?{/ 1>

2 个答案:

答案 0 :(得分:6)

Javadoc中提到了这些类之间的差异,以及何时使用其中一个类。来自LongAdder

  

当多个线程更新用于收集统计信息但不用于细粒度同步控制的目的的公共和时,此类通常优于AtomicLong。在低更新争用下,这两个类具有相似的特征。但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高。

来自LongAccumulator

  

当多个线程更新用于收集统计信息但不用于细粒度同步控制的目的的公共值时,此类通常优于AtomicLong。在低更新争用下,这两个类具有相似的特征。但在高争用的情况下,这一类的预期吞吐量明显更高,但代价是空间消耗更高。

     

[...]

     

LongAdder提供了此类功能的类比,用于维护计数和总和的常见特殊情况。致电new LongAdder()相当于new LongAccumulator((x, y) -> x + y, 0L)

因此,使用一个而不是另一个取决于您的应用程序打算做什么。它并不总是严格优先考虑,只有在预期高并发并且您需要维持一个共同状态时才会优先考虑。

答案 1 :(得分:1)

@Tunaki熟练地回答了这个问题,但仍有一个问题影响了选择。

添加到单元格需要每个线程一个单元格。内部代码使用Striped64中的getProbe()返回:

  

返回UNSAFE.getInt(Thread.currentThread(),PROBE);

Probe是threadLocalRandomSeed中使用的系统字段。

我的理解是探针对于每个线程都是唯一的。如果你有大量的线程创建/销毁,那么为每个新线程创建探针。

因此,细胞数量可能过多。如果有人有更详细的信息,我想听听你的意见。