[concurrency-interest] LongAdder with custom behavior?

Peter Levart peter.levart at gmail.com
Sat Dec 2 07:00:34 EST 2017

Hi Carl,

Carl Mastrangelo je 01. 12. 2017 ob 20:12 napisal:
>     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.
> This approach would work, but why wouldn't sumThenReset implement it 
> that way?     It isn't clear to me that two volatile accesses is 
> faster than a single CAS.

The name I gave - 'sumThenResetAtomic' is not correct. There's nothing 
atomic about the method. If one wanted to use it as is in a concurrent 
environment it should at least be synchronized so that concurrent 
threads calling it do the right thing - to support your use case.

So my answer is speculative: probably because it would require 
synchronization and LongAdder was designed to not use any locks. If one 
wants to do it that way, (s)he can. LongAdder is just a low-level 
primitive with which you can build your concurrent logic.

I'm wondering why you need a fail-fast isEmpty() method though. Do you 
need to call it frequently? Why?

Regards, Peter

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

More information about the Concurrency-interest mailing list