[concurrency-interest] LongAdder with custom behavior?

Martin Buchholz martinrb at google.com
Fri Dec 1 14:27:28 EST 2017

It looks like we should be taking advantage of other VarHandle features,
e.g. calling getAndAddRelease

On Fri, Dec 1, 2017 at 11:18 AM, Martin Buchholz <martinrb at google.com>

> It seems straightforward to use VarHandle getAndSet methods in LongAdder
> (and Striped64) and should be strictly more efficient.   I would
> write sumThenReset like this:
>     /**
>      * Equivalent in effect to {@link #sum} followed by {@link #reset}.
>      * This method may apply for example during quiescent points
>      * between multithreaded computations.  If there are updates
>      * concurrent with this method, the returned value is <em>not</em>
>      * guaranteed to be the final value occurring before the reset.
>      *
>      * @return the sum
>      */
>     public long sumThenReset() {
>         final Cell[] cells = this.cells;
>         long sum = getAndSetBase(0L);
>         if (cells != null)
>             for (Cell cell : cells)
>                 if (cell != null)
>                     sum += cell.getAndSet(0L);
>         return sum;
>     }
> With the use of getAndSet, we can then consider using sumThenReset for
> concurrency control.  A consumer can "harvest" counts that have collected
> in the LongAdder in Semaphore style, without losing any concurrent counts.
> The hard part is writing the spec!  Unfortunately the name sumThenReset
> becomes a bit of a misnomer as it strongly implies non-thread-safety and
> use of reset().
> On Thu, Nov 30, 2017 at 11:18 PM, Carl Mastrangelo via
> Concurrency-interest <concurrency-interest at cs.oswego.edu> 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.
>> 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.
>> 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/ff1eef41/attachment-0001.html>

More information about the Concurrency-interest mailing list