[concurrency-interest] LongAdder with custom behavior?

Peter Levart peter.levart at gmail.com
Fri Dec 1 03:07:46 EST 2017


Hi Carl,

On 12/01/2017 08:18 AM, Carl Mastrangelo via Concurrency-interest wrote:
> While looking at LongAdder as a possible candidate for a concurrent 
> counter, I noticed three things that made it seem surprising.  I am 
> wondering what the rationale is for these since they don't make sense 
> to me:
>
> 1.  LongAdder.sumThenReset seems to not be thread-safe.  If concurrent 
> writes happen between reading and resetting of each Cell, then the 
> write could get dropped.    This matches the behavior described in 
> reset(), but makes the class less useful.   For instance, I would like 
> sumThenReset to tally up all the mutations, and reset the counter back 
> to zero without dropping mutations.  This would make it so I call 
> sumThenReset later, and pick up any mutations I missed.
>
> 2.  Following up on the first point, the implementation of 
> sumThenReset does two volatile operations on each Cell.value. First it 
> reads, followed by setting it to zero.  Why doesn't it use getAndSet 
> on the value?  On the surface it would appear to be fewer 
> synchronization points.   Also, it would nicely solve the first item.

You can achieve similar observable effect in the following way:

     public static long sumThenResetAtomic(LongAdder adder) {
         long sum = adder.sum();
         adder.add(-sum);
         return sum;
     }

This has better performance, because it does N reads and potentially 
only a single CAS which presents less disturbance to concurrent ongoing 
additions than N getAndSet(s) would.

>
> 3.   In the case that the LongAdder only ever increases in value (no 
> resets), it would be possible to provide a means to see if it's equal 
> to zero.  I believe this would be cheaper to implement than summing 
> across all Cells.  The list of cells could be walked until there was a 
> single nonzero cell, at which point it could return early.  This would 
> be similar to the isEmpty() method on ConcurrentLinkedQueue, which 
> doesn't need to walk the whole list.

if you are talking about adder.isEmpty() being a cheaper variant of 
(adder.sum() == 0L), then all cells have to be summed in any case. 
Imagine an adder with 2 cells:

cell[0] == 42L
cell[1] == -42L

Regards, Peter

>
> The reason I bring this up is that although the LongAdder class is 
> non-final, there is no way to provide an isEmpty() myself.  All the 
> access to the Cells and value are package private.  If I did implement 
> this, I would have to give up the nice contention features.
>
> Is LongAdder reusable or should I try making my own counter?  Also, 
> were the issues I bring up now brought up during the design?
>
> Carl
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20171201/ee61d7ca/attachment.html>


More information about the Concurrency-interest mailing list