All else equal, prefer getAndIncrement()
Some CPUs support it directly (even when the return address is used), unlike incrementAndGet(), so you might save one inc reg instruction if the return value is used.
The portable CAS retry loop isn't the implementation actually used on real JVMs for mainstream ISAs that have instructions for this. At least I hope not!
If your JVM is any good, these will compile + JIT to a single instruction on x86 or ARMv8.1.
If the return value isn't used, either can be x86 lock inc dword [mem]
If the return value is used (or the optimizer doesn't know this peephole), getAndIncrement() is the same operation as C++ fetch_add(1), which is x86 lock xadd [mem], reg (exchange-and-add) or ARMv8.1 ldadd (or ldaddal for the seq_cst version).
There is no single-instruction IncAndGet; you need a separate add or inc reg if you want that. But if you don't use the return value, hopefully a compiler can still omit that even if it uses lock xadd instead of
For example in C:
#include <stdatomic.h> void Inc(_Atomic int *p) { ++*p; } int GetAndInc(_Atomic int *p) { //return atomic_fetch_add_explicit(p, 1, memory_order_relaxed); return (*p)++; // uses seq_cst like Java is stuck with } int IncAndGet(_Atomic int *p) { //return 1 + atomic_fetch_add_explicit(p, 1, memory_order_relaxed); return ++*p; }
AArch64 assembly (from Godbolt, Clang 19 -O2 -mcpu=cortex-a77)
Inc: mov w8, #1 ldaddal w8, w8, [x0] // Load+ADD Acquire reLease ret GetAndInc: mov w8, #1 ldaddal w8, w0, [x0] ret IncAndGet: mov w8, #1 ldaddal w8, w8, [x0] add w0, w8, #1 // turn fetch_add result into add_fetch ret
Same for x86-64
Inc: lock inc dword ptr [rdi] ret GetAndInc: mov eax, 1 lock xadd dword ptr [rdi], eax ret IncAndGet: mov eax, 1 lock xadd dword ptr [rdi], eax inc eax ret
On ISAs without single-instruction RMWs, like ARMv7 and ARMv8.0, or MIPS or PowerPC or I think RISC-V, there's no difference, or if anything incrementAndGet needs fewer spare registers since it can overwrite the load result with the add result. Same number of instructions either way for ARMv8.0 when told to inline the old-style instructions instead of calling libatomic helper functions in the hope that ARMv8.1 instructions will be available at run-time even if we don't want to require them (-mno-outline-atomics = inline atomics). These functions aren't running short on registers, only limited by needing the return value in the same register as the incoming pointer.
# AArch64 clang -O2 -Wall -mcpu=cortex-a53 -mno-outline-atomics GetAndInc: .LBB1_1: ldaxr w8, [x0] // load-acquire exclusive add w9, w8, #1 // add into a different register stlxr w10, w9, [x0] // store-release exclusive cbnz w10, .LBB1_1 mov w0, w8 ret IncAndGet: .LBB2_1: ldaxr w8, [x0] add w8, w8, #1 // overwrite the load result stlxr w9, w8, [x0] cbnz w9, .LBB2_1 mov w0, w8 ret
My recommendation at the top of the answer to favour getAndIncrement() is based on the fact that if an ISA provides a single-instruction atomic, it's normally a fetch_add not an add_fetch. And that is the case on the two most common mainstream ISAs, x86-64 and AArch64.
as well as which would put less load in CPU caches getting synchronized
Absolutely no difference. The atomic RMW is the same either way, it's just a question of whether you need to fix-up the result for local use.
Fun fact: GNU C __atomic builtins also come in both flavours, __atomic_fetch_add and __atomic_add_fetch. (https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html#index-_005f_005fatomic_005fadd_005ffetch).
AtomicInteger.getAndIncrement()two threads will get the same value?getAndIncrement.compareAndSet()only one thread (the winner) will return. This winner will return the version that matched the version that the thread saw at the beginning of the spin.comapreAndSet()because the version of the atomic value will no longer match the one they saw when the first.get()at the beginning of their respective spin-locks was made, and so they will retry, on their next spin their "current" will finally reflect the change, so the answer is: No,AtomicInteger.getAndIncrement()will never bring the same value even under heavy contention.