Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java 8 : Are LongAdder and LongAccumulator preferred to AtomicLong?

LongAdder as an alternative to 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 is a more generalized version of 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

I have some queries.

  1. Is LongAdder always preferred to AtomicLong?
  2. Is LongAccumulator preferred to both LongAdder and AtomicLong?
like image 707
Ravindra babu Avatar asked Feb 08 '23 15:02

Ravindra babu


2 Answers

The difference between those classes, and when to use one over the other, is mentioned in the Javadoc. From LongAdder:

This class is usually preferable to AtomicLong when multiple threads update a common sum that is used for purposes such as collecting statistics, not for fine-grained synchronization control. Under low update contention, the two classes have similar characteristics. But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.

And from LongAccumulator:

This class is usually preferable to AtomicLong when multiple threads update a common value that is used for purposes such as collecting statistics, not for fine-grained synchronization control. Under low update contention, the two classes have similar characteristics. But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.

[...]

Class LongAdder provides analogs of the functionality of this class for the common special case of maintaining counts and sums. The call new LongAdder() is equivalent to new LongAccumulator((x, y) -> x + y, 0L).

Thus, the use of one over the other depends on what your application intends to do. It is not always strictly prefered, only when high concurrency is expected and you need to maintain a common state.

like image 151
Tunaki Avatar answered Feb 13 '23 22:02

Tunaki


@Tunaki answered the question skillfully, but there is still one issue that affects the choice.

Adding to a Cell requires a Cell per thread. The internal code uses getProbe() in Striped64 which returns:

return UNSAFE.getInt(Thread.currentThread(), PROBE);

Probe is a system field used in threadLocalRandomSeed.

My understanding is that probe is unique for each thread. If you have a high number of threads create/destroy then probe is created for each new thread.

Therefore, the number of Cells may become excessive. If someone has more detail on this I would like to hear from you.

like image 35
edharned Avatar answered Feb 13 '23 22:02

edharned