Medium👤 3-5 years👤 8-15 years 3 min read

ConcurrentHashMap Compound Operations — Interview Questions

Asked inAmazonMicrosoftGoogleDeloitte
#concurrenthashmap#compound operations#computeifabsent#merge#race condition
Report issue

⚡ Short Answer

ConcurrentHashMap guarantees each individual method call (get, put, remove) is thread-safe — but a get() followed by a put() based on that result is two separate operations with a window between them where another thread can interleave, the same check-then-act race a plain HashMap has, just with a thread-safe map underneath it. computeIfAbsent(), compute(), and merge() close that window because the whole read-modify-write happens atomically under the map's internal per-bin lock, as a single operation.

Coffee Chat Question

Concept Made Simple

ConcurrentHashMap is thread-safe — so why can a get-then-put sequence still race, and how do computeIfAbsent/merge fix it?

🧠Mind Map Answer

Remember It Faster

'Thread-safe' on a ConcurrentHashMap means each *individual* method call is atomic and safely published across threads — it says nothing about a sequence of calls you compose yourself. if (!map.containsKey(k)) map.put(k, v) is exactly as racy as it would be on a plain HashMap; the map's internal safety doesn't extend across your own multi-statement logic.

get() then put()Two separate atomic ops — a race window exists between them
computeIfAbsent()Atomic: check-and-insert as ONE operation, no window
merge()Atomic: combine-or-insert as ONE operation
CaveatThe mapping function itself should be fast — it runs while holding a lock on that bin

Key takeaway: thread-safety is per-call, not per-transaction — any time your logic spans more than one map call, reach for the compound methods instead of composing get/put yourself.

⌨️Hands-on Keyboard

Learn by Doing

java
ConcurrentHashMap<String, List<String>> index = new ConcurrentHashMap<>();

// RACY: two threads can both see containsKey()==false and both create a new list
if (!index.containsKey(key)) {
    index.put(key, new ArrayList<>());
}
index.get(key).add(value);   // also unsafe if the List itself isn't thread-safe

// CORRECT: atomic check-and-insert, single operation
index.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>()).add(value);

🔥What If?

Think Beyond the Expected

What happens if the mapping function passed to computeIfAbsent() is slow or tries to modify the same map?

It runs while the map holds a lock on that key's bin, so a slow function blocks other threads touching keys in the same bin. Modifying the same map from inside its own mapping function is not a safe, supported pattern — the JDK documents this as unsupported, and doesn't guarantee what happens: depending on the exact operation it can manifest as blocked/hung threads, an exception, or other incorrect behavior. The rule to follow isn't 'expect exception X' — it's simply: never touch the same map from within its own mapping function.

😂Real World

This is the classic 'we used ConcurrentHashMap so it must be safe' bug — a caching layer built on get()-then-put() under load creates duplicate cache entries or, worse, wraps the value in a non-thread-safe collection (a plain ArrayList) that then corrupts under concurrent add() calls even though the outer map was never the problem.

🗣️Real Talk from Guru

In an interview I'd say: swapping HashMap for ConcurrentHashMap fixes the map's internal safety, but it doesn't automatically fix your algorithm — if your logic reads then writes based on that read, you need computeIfAbsent/merge/compute, full stop.

🎯Interviewer's Expectation

Keywords they're listening for:

Distinguishes per-method thread-safety from multi-step compound safetyCan name and use computeIfAbsent/merge/compute correctlyKnows the mapping function runs under a per-bin lockWarns against slow or recursive mapping functions

⚠️Common Mistakes

  • Composing get()/containsKey() and put() as if the sequence were atomic
  • Storing a non-thread-safe collection as the map's value
  • Writing slow or map-mutating logic inside a mapping function

Best Practices

  • Use computeIfAbsent/compute/merge for any read-modify-write on a shared map
  • Keep mapping functions fast and free of side effects on the same map
  • Pair with a thread-safe value type (CopyOnWriteArrayList, another ConcurrentHashMap) when needed

🔁Follow-up Questions

  • 1What's the difference between compute() and computeIfAbsent()?
  • 2Why must the value type stored (e.g. a List) also be thread-safe on its own?
  • 3What happens if two threads call computeIfAbsent() with the same key simultaneously?

🧩Related Technologies

HashMapAtomicReferencecompute

Continue Learning with AI

Take this question deeper with your favourite AI assistant. Pick a depth, copy the prompt, or open it directly — AI is your learning companion, not a shortcut.

Plain-language foundations

I'm preparing for a software engineering interview and want to understand this from scratch, as a beginner.

Topic: ConcurrentHashMap (Java Collections)
Interview question: "ConcurrentHashMap is thread-safe — so why can a get-then-put sequence still race, and how do computeIfAbsent/merge fix it?"

Please:
1. Explain the core idea in simple, plain language, using an everyday analogy.
2. Define any technical terms you use.
3. Walk through one small, concrete example.
4. Finish with a single sentence I can easily remember.

Keep the tone friendly and assume I'm new to this topic.
Open inChatGPTGeminiClaude

Was this answer helpful?

Support our platform by exploring our recommended products.

As an Amazon affiliate, purchases through these links may earn us a small commission — at no extra cost to you. It helps keep Full Stack Interview Guru free.

Related Questions