[concurrency-interest] AtomicReference.updateAndGet() mandatory updating

Brian S O'Neill bronee at gmail.com
Wed May 24 18:51:16 EDT 2017


Have you had a chance to take a look at the Java 9 version of this method?

     public final V updateAndGet(UnaryOperator<V> updateFunction) {
         V prev = get(), next = null;
         for (boolean haveNext = false;;) {
             if (!haveNext)
                 next = updateFunction.apply(prev);
             if (weakCompareAndSetVolatile(prev, next))
                 return next;
             haveNext = (prev == (prev = get()));
         }
     }

It doesn't omit the CAS, but it does omit calling the function 
needlessly if prev hasn't changed. I wonder what effect the weak CAS 
has. For which platforms does it make a difference?


On 2017-05-23 04:58 PM, Mike Duigou wrote:
> Currently the AtomicReference updateAndGet implementation will 
> unconditionally perform a compareAndSet using the result of the update 
> function.
> 
> public final V updateAndGet(UnaryOperator<V> updateFunction) {
>    V prev, next;
>    do {
>      prev = get();
>      next = updateFunction.apply(prev);
>    } while (!compareAndSet(prev, next));
>    return next;
> }
> 
> I find that I write a lot of update functions which only occasionally 
> change the value. For these cases I wonder if it would be reasonable to 
> skip the update if the value of next is unchanged from previous. A 
> proposed alternative (there are analogues for Integer and Long).
> 
> public final V updateAndGet(UnaryOperator<V> updateFunction) {
>    V prev, next;
>    do {
>      prev = get();
>      next = updateFunction.apply(prev);
>    } while (prev != next && !compareAndSet(prev, next));
>    return next;
> }
> 
> The cases to consider are:
> 
> 1. prev == value == next :: Nothing changed.
> 
> In this case omitting the compareAndSet is a useful optimization. No 
> difference for external observer.
> 
> 
> 2. (prev == value) != next :: Only next changed
> 
> In this case the compareAndSet would be performed and succeed as prev == 
> value. No difference for external observer.
> 
> 
> 3. prev != value != next :: Both next and value changed. A concurrent 
> modification.
> 
> In this case the compareAndSet would be performed and will fail as prev 
> != val. No difference for external observer.
> 
> 
> 4. (prev == next) != value :: Only value changed. A concurrent 
> modification.
> 
> In the original implementation the compareAndSet would fail resulting in 
> another update attempt. In proposed implementation the compareAndSet 
> would not be attempted and the value returned would be unchanged. The 
> concurrent modification of value is ignored. Surely this is wrong! It 
> appears wrong because some other thread beat us and updated the value. 
> The question is whether our thread could tell the difference between the 
> call it made to updateAndGet completing first and a concurrent update 
> being ignored. Other than via side-effects in updateFunction it does not 
> appear that it could. To an external observer this case is 
> indistinguishable from the first where there was no concurrent update. 
> Even if there is a concurrent update it will appear to callers that 
> non-mutating updates always completed first.
> 
> Useful? Wrongheaded?
> 
> Mike
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest


More information about the Concurrency-interest mailing list