concurrency
atomicity
programming
i++
multithreading

Why is i not atomic?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

i++ looks like one tiny operation in source code, but in concurrent programming what matters is the underlying read-modify-write sequence. Because that sequence can be interrupted or interleaved with work from another thread, i++ is generally not atomic unless the language or library gives you a special atomic increment primitive.

What i++ Expands Into

Conceptually, i++ does three things:

  1. read the current value of i
  2. add one
  3. write the new value back

Those steps are enough to create a race condition.

java
counter++;

Even though that is a single source line, the operation may behave more like:

text
load counter
increment register
store counter

If two threads do that at the same time, both may read the same old value before either write happens.

The Lost Update Problem

Suppose i starts at 5 and two threads both execute i++.

  • thread A reads 5
  • thread B reads 5
  • thread A writes 6
  • thread B writes 6

The final result is 6, even though two increments happened. One update was lost.

That is exactly why non-atomic increments are dangerous in shared mutable state.

Atomic Means Indivisible From Other Threads' Perspective

An atomic operation appears to happen as one indivisible step with respect to other threads. No other thread can observe the operation halfway through or slip a conflicting update in between the read and write.

In Java, one common fix is AtomicInteger:

java
1import java.util.concurrent.atomic.AtomicInteger;
2
3AtomicInteger counter = new AtomicInteger(0);
4counter.incrementAndGet();

This is different from plain counter++ on an int, because the atomic class provides synchronization guarantees around the increment itself.

volatile Does Not Solve This

Many developers think volatile makes i++ atomic. It does not. volatile helps with visibility, meaning threads see recent writes more reliably, but it does not turn a read-modify-write sequence into one indivisible update.

So this is still unsafe for concurrent increments:

java
volatile int counter = 0;
counter++;

The read and write are more visible, but the race between them still exists.

Locks Are Another Correct Solution

You can also make increments safe with a lock:

java
1private final Object lock = new Object();
2private int counter = 0;
3
4public void increment() {
5    synchronized (lock) {
6        counter++;
7    }
8}

This works because only one thread at a time can enter the critical section, so the read-modify-write sequence is protected from interleaving.

Source-Level Simplicity Is Misleading

One of the hardest parts of concurrency is that short code is not necessarily simple code. i++ is a perfect example. It feels like a primitive action, but at the machine and memory-model level it is a compound operation whose safety depends on the execution context.

That is why concurrency reasoning has to focus on memory access patterns, not just on the number of tokens in the source line.

Common Pitfalls

The biggest pitfall is assuming that because i++ is one expression, it must be one atomic action. Source-code brevity tells you nothing about thread-safety.

Another common mistake is using volatile as though it were a substitute for atomic updates. Visibility and atomicity are different guarantees.

Developers also underestimate how often these races happen. A shared counter may look correct under light testing and fail only under real concurrency, which makes the bug feel random even though the data race is deterministic in principle.

Summary

  • 'i++ is usually a read-modify-write sequence, not one indivisible atomic action.'
  • Two threads can interleave those steps and lose updates.
  • 'volatile improves visibility but does not make increments atomic.'
  • Use atomic types or locks when multiple threads update shared counters.
  • In concurrency, a one-line expression can still hide a multi-step race condition.

Course illustration
Course illustration

All Rights Reserved.