DEV Community

Machine coding Master
Machine coding Master

Posted on Originally published at javalld.com

Thread-Safe Counter in Java: Fix Your First Concurrency Bug in Machine Coding

Thread-Safe Counter in Java: Fix Your First Concurrency Bug in Machine Coding

During high-pressure machine coding interviews, seemingly trivial building blocks are where candidates quietly introduce race conditions that fail multi-threaded verification tests. A standard counter looks deceptively simple, but failing to handle concurrent mutation immediately signals a lack of production-grade Java depth to senior interviewers.

The Mistake Most Candidates Make

  • Assuming count++ is an atomic instruction; at the bytecode level, it is a non-atomic read-modify-write sequence (getfield, iadd, putfield).
  • Declaring volatile int count = 0; under the false impression that visibility guarantees atomicity; it syncs cache lines across CPU cores but does not stop interleaved updates.
  • Defaulting to heavy synchronized blocks around simple scalar updates, introducing unnecessary lock contention and context-switching overhead.

The Right Approach

  • Treat state mutations as atomic transactions that guarantee both memory visibility and uninterrupted execution across threads.
  • AtomicInteger, LongAdder, ReentrantLock
  • Lock-free primitives leverage hardware-level Compare-And-Swap (CAS) instructions to eliminate race conditions without suspending threads.

Heads up: if you want to see these patterns applied to real interview problems, javalld.com has full machine coding solutions with traces.

The Key Insight (Code)

import java.util.concurrent.atomic.AtomicInteger;

public class ThreadSafeCounter {
    private final AtomicInteger count = new AtomicInteger(0);

    // Lock-free atomic increment using hardware CAS
    public int increment() {
        return count.incrementAndGet();
    }

    public int get() {
        return count.get();
    }
}
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  • count++ is non-atomic; concurrent threads will interleave during execution, leading to lost increments and non-deterministic results.
  • volatile fixes the cache visibility problem, but it cannot make compound read-modify-write operations thread-safe.
  • Use AtomicInteger for standard thread-safe counting, and consider LongAdder for high-throughput write-heavy scenarios to reduce CAS contention.

Full working implementation with execution trace available at https://javalld.com/learn/thread-counter

Top comments (0)