JVM.Thread.How AtomicInteger works under the hood ?

How AtomicInteger Works Under the Hood

AtomicInteger is a thread-safe, lock-free alternative to int that allows atomic operations without using synchronized or explicit locks. It relies on low-level CPU instructions (CAS – Compare-And-Swap) to ensure atomicity.


1. Why Use AtomicInteger?

In a multithreaded environment, updating a regular int like this:

private int count = 0;

public void increment() {
    count++; // Not thread-safe!
}

🚨 Not thread-safe!

  • If multiple threads execute count++ at the same time, they might read the same old value and overwrite each other’s updates.
  • This is a race condition.

✅ Instead, using AtomicInteger ensures thread safety without locking:

private AtomicInteger count = new AtomicInteger(0);

public void increment() {
    count.incrementAndGet(); // Thread-safe
}

2. How AtomicInteger Works Internally

Unlike synchronized, which locks the entire method, AtomicInteger uses lock-free atomic operations via Compare-And-Swap (CAS).

CAS (Compare-And-Swap) Mechanism

  1. Read the current value (oldValue).
  2. Calculate the new value (newValue).
  3. Use CAS to update the value only if no other thread changed it.
    • If successful → update applied.
    • If failed → retry until successful.

Key Internal Methods

A. incrementAndGet() (Atomic Increment)

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

🔍 What happens under the hood?

  • Uses Unsafe.getAndAddInt(), which performs a CAS operation to safely increment the value.

B. compareAndSet() (CAS Operation)

public final boolean compareAndSet(int expected, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expected, update);
}

If expected == currentValue, update it to update.Otherwise, another thread has modified it, so retry.

3. Performance Advantage: Why No Locks?

Instead of synchronized, AtomicInteger relies on CPU instructions:

  • CAS (cmpxchg on x86 CPUs) is executed in hardware, making it much faster than locks.
  • No context switching (which happens with locks).
  • Reduces blocking and contention in multi-threaded environments.

🔹 Example: incrementAndGet() vs. synchronized

ApproachPerformanceBlocking?
synchronizedSlower✅ Yes
AtomicIntegerFaster❌ No

4. When Should You Use AtomicInteger?

Use AtomicInteger when:

  • You need simple atomic updates (counters, flags).
  • You want better performance than synchronized in a concurrent environment.
  • Example: Thread-safe countersjavaCopyEdit
private AtomicInteger counter = new AtomicInteger(0);

public void increment() {
    counter.incrementAndGet(); // Fast & thread-safe
}

Don’t use AtomicInteger when:

  • You need compound operations (multiple related updates).
  • Example: If you have a balance that requires checking before updating, AtomicInteger alone is not enough.

🔹 For multiple related updates, use synchronized or ReentrantLock instead.

private int balance = 0; public synchronized void deposit(int amount) { if (amount > 0) { balance += amount; // Ensures atomicity } }

5. Summary

FeaturesynchronizedAtomicInteger
PerformanceSlower (uses locks)Faster (lock-free)
Thread Safety✅ Yes✅ Yes
Blocking?✅ Yes (may cause thread contention)❌ No (uses CAS)
Best ForComplex updates, multiple variablesSimple atomic operations

Final Thoughts

  • AtomicInteger is fast, but it’s not always a replacement for synchronized.
  • It works best for single-value atomic updates.
  • For complex operations, you still need locks.
This entry was posted in Без рубрики. Bookmark the permalink.