DEV Community

Nikhil Kamani
Nikhil Kamani

Posted on

Your ConcurrentHashMap Is Thread-Safe. Your Code Still Isn't.

I've interviewed hundreds of developers, and this question catches a lot of them because the code looks perfectly safe.

ConcurrentHashMap<String, Integer> counts = new ConcurrentHashMap<();
counts.put("A", 1);

if (counts.get("A") != null) {
    counts.put("A", counts.get("A") + 1);
}
Enter fullscreen mode Exit fullscreen mode

We're using ConcurrentHashMap. So this is thread-safe, right?
Not necessarily !!!

The problem

ConcurrentHashMap makes each individual operation thread-safe, get(), put(), remove(). It does not make a sequence of operations atomic.

get() and put() here are two separate steps. If two threads run this block at the same time:

Both read A = 1
Both compute 1 + 1 = 2
Both write A = 2
Expected result: 3. Actual result: 2. One update silently disappears.

The fix

Use an operation that reads and updates in one atomic step:

counts.merge("A", 1, Integer::sum);
or
counts.compute("A", (key, value) -> value == null ? 1 : value + 1);

Now the read-modify-write happens as a single atomic operation on that key.

The interview lesson

Weak answer: "It's a ConcurrentHashMap, so it's thread-safe."

Strong answer: "Individual operations are thread-safe, but a sequence of operations isn't automatically atomic."

Rule of thumb: any time you see read → calculate → write, ask if another thread could change the value in between. If yes, you likely have a race condition, no matter which "thread-safe" class you're using.

Have you run into a ConcurrentHashMap race condition like this, in production or in an interview?

Top comments (0)