Reputation: 24157
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?
Upvotes: 5
Views: 822
Reputation: 447
As discussed in link provided by Jim, in Java 8 incrementAndGet and other methods are taking advantage of hardware support for "lock, fetch and add" instruction.
Upvotes: 0
Reputation: 98284
unsafe.getAndAddLong
is JVM intrinsic which is translated by JIT into an optimized instruction sequence. On x86 it is just a single CPU instruction LOCK XADD
.
Upvotes: 5
Reputation: 86764
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.
Upvotes: 6