[concurrency-interest] JDK 9's compareAndSet vs compareAndExchange

Aleksey Shipilev shade at redhat.com
Thu Sep 22 10:20:21 EDT 2016


Hi,

Somewhat counter-intuitively, reusing compareAndExchange return value as
the basis for retry is slower than re-reading actual value for
compareAndSet. Because under contention, the overall progress depends on
the width on the "collision window" for your RMW operation:
 https://bugs.openjdk.java.net/browse/JDK-8141640

compareAndExchange is useful when you *have* to have the "witness value"
against which you failed. Choosing compareAndExchange over compareAndSet
within the loop is futile. Choosing compareAndExchange *instead* of
compareAndSet + re-reads is sane, e.g. in
https://github.com/boundary/high-scale-lib/blob/master/src/main/java/org/cliffc/high_scale_lib/NonBlockingHashMap.java#L583

Thanks,
-Aleksey

On 09/22/2016 03:35 PM, Dávid Karnok wrote:
> JDK 9's VarHandle API (and AtomicXXX classes) specify the new
>  compareAndExchange() method. Traditionally, I wrote CAS loops like this:
> 
> public static long getAddAndCap(AtomicLong requested, long n) {
>     for (;;) {
>         long current = requested.get();
> 
>         if (current == Long.MAX_VALUE) {
>            return Long.MAX_VALUE;
>         }
>         long next = current + n;
>         if (next < 0L) {
>             next = Long.MAX_VALUE;
>         }
>         if (requested.compareAndSet(current, next)) {
>             return current;
>         }
>     }
> }
> 
> Now I can write this:
> 
> public static long getAddAndCap(AtomicLong requested, long n) {
>     long current = requested.get();
>     for (;;) {
> 
>         if (current == Long.MAX_VALUE) {
>            return Long.MAX_VALUE;
>         }
>         long next = current + n;
>         if (next < 0L) {
>             next = Long.MAX_VALUE;
>         }
>         long actual = requested.compareAndExchange(current, next);
>         if (actual == current) {
>            return current;
>         }
>         current = actual;
>     }
> }
> 
> I'm not sure I could JMH benchmark these under JDK 9 now so my question
> is whether the latter pattern has lower overhead (on x86) since it
> reuses the value returned by the underlying LOCK CMPXCHG instead of
> re-reading the target field again (or the JIT was always smart enough to
> detect the unnecessary re-read with compareAndSet; or the hardware is
> smart enough by doing speculative reads in this case to hide its latency ?).
> 
> -- 
> Best regards,
> David Karnok
> 
> 
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20160922/3959749c/attachment.sig>


More information about the Concurrency-interest mailing list