[concurrency-interest] AtomicReference.updateAndGet() mandatoryupdating

David Holmes davidcholmes at aapt.net.au
Tue May 23 20:47:58 EDT 2017


No you are right – the difference in behavior is not observable (except perhaps by the updateFunction – which would be odd in itself).

 

I’m used to cases where there will always be a change in value. 😊

 

David

 

From: Concurrency-interest [mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf Of David Holmes
Sent: Wednesday, May 24, 2017 10:29 AM
To: 'Dmitry Zaslavsky' <dmitry.zaslavsky at gmail.com>; 'Mike Duigou' <openjdk at duigou.org>; 'Concurrency Interest' <concurrency-interest at cs.oswego.edu>
Subject: Re: [concurrency-interest] AtomicReference.updateAndGet() mandatoryupdating

 

The value may change as soon as compareAndSet succeeds but at least you know that the value did not change after the get() and you did not miss an update that you should have “corrected”. Obviously depending on how you use this API this may be a non-issue, but the API doesn’t know your usecase.

 

David

 

From: Dmitry Zaslavsky [mailto:dmitry.zaslavsky at gmail.com] 
Sent: Wednesday, May 24, 2017 10:20 AM
To: dholmes at ieee.org <mailto:dholmes at ieee.org> ; 'Mike Duigou' <openjdk at duigou.org <mailto:openjdk at duigou.org> >; 'Concurrency Interest' <concurrency-interest at cs.oswego.edu <mailto:concurrency-interest at cs.oswego.edu> >
Subject: RE: [concurrency-interest] AtomicReference.updateAndGet() mandatoryupdating

 

I don’t see how this is more racy than the original code…

As soon as you call compareAndSet() the value might have changed.

 

I have a place in my code, where this make a significant performance difference on x86.

Volatile read is just a read and a single compare with predicted branch returns most of the time.

 

Sent from Mail <https://go.microsoft.com/fwlink/?LinkId=550986>  for Windows 10

 

From: David Holmes <mailto:davidcholmes at aapt.net.au> 
Sent: Tuesday, May 23, 2017 8:16 PM
To: 'Mike Duigou' <mailto:openjdk at duigou.org> ; 'Concurrency Interest' <mailto:concurrency-interest at cs.oswego.edu> 
Subject: Re: [concurrency-interest] AtomicReference.updateAndGet() mandatoryupdating

 

Hi Mike,

 

What you suggest is too racy. As soon as you call get() the value may change such that you do want to update it - even if back to what it was previously. Only by doing the CAS can you be sure that nothing changed and you truly updated things in the manner expected.

 

Cheers,

David

 

> -----Original Message-----

> From: Concurrency-interest [mailto:concurrency-interest-bounces at cs.oswego.edu] On Behalf Of Mike Duigou

> Sent: Wednesday, May 24, 2017 9:59 AM

> To: Concurrency Interest <concurrency-interest at cs.oswego.edu <mailto:concurrency-interest at cs.oswego.edu> >

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

> 

> 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 <mailto:Concurrency-interest at cs.oswego.edu> 

> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

 

_______________________________________________

Concurrency-interest mailing list

Concurrency-interest at cs.oswego.edu <mailto: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/20170524/f2a13b9b/attachment.html>


More information about the Concurrency-interest mailing list