Prior to Java 8 the code for CAS in AtomicLong class was:
public final long incrementAndGet() {
for (;;) {
long current = get();
long next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
But now it has been changed to single intrinsic line:
public final long incrementAndGet() {
return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}
What advantage this code has over the former? How does this new code work?
The reason is branch prediction on the loop. Under high contention the CAS loop fails often and the branch predictor starts to predict the execution path will stay in the loop, causing lots of pipeline flushing when the CAS eventually succeeds. Also this speeds up the loop when what you really want is a backoff when CAS fails, not a speedup.
See https://blogs.oracle.com/dave/entry/atomic_fetch_and_add_vs for a more detailed treatment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With