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

Mike Duigou openjdk at duigou.org
Tue May 23 19:58:40 EDT 2017


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


More information about the Concurrency-interest mailing list