Interview replay
Full round replay — ConcurrentHashMap
Timed verbal replay with pass/fail criteria per follow-up.
How to run this
The opener
“How does ConcurrentHashMap achieve thread safety?”
Budget: 45 seconds. Going long here is itself a fail signal.
Follow-ups
1. “Where exactly is the lock taken on a write?”
Testing: Bin-level, or a vague 'it locks internally'?
Scoring
Pass: On an occupied bin, synchronized on that bin's head node. On an empty bin, no lock at all — a CAS installs the first node. If the bin is being transferred, the writer helps the resize rather than blocking.
Fail: Says it locks the map, or cannot say what is locked.
2. “How did this work before Java 8?”
Testing: The answer that dates a candidate if given as the current one.
Scoring
Pass: An array of segments, each an independent ReentrantLock over a slice of the table, with the count fixed at construction by concurrencyLevel — default 16. That capped concurrent writers at 16 whatever the map's size.
Fail: Describes segments as the current design.
3. “Do reads take a lock?”
Testing: Whether they know why not.
Scoring
Pass: No. The node's value and next pointer are volatile, so a read is a plain volatile read guaranteed to see completed writes.
Fail: Says reads take a read lock or a shared lock.
4. “Is `if (!map.containsKey(k)) map.put(k, v)` safe here?”
Testing: The question that separates users from readers.
Scoring
Pass: No. Each call is atomic, the pair is not — another thread can insert in the gap. Use putIfAbsent or computeIfAbsent, which do the check and insert inside the bin lock.
Fail: Says yes because the map is thread-safe.
5. “Which compound method for a counter?”
Testing: Do they know merge exists?
Scoring
Pass: merge(key, 1, Integer::sum). get-then-put is a read-modify-write and loses increments exactly like count++.
Fail: Reaches for getOrDefault then put, or synchronizes the method.
6. “Why does it reject null keys and values?”
Testing: The reasoning, not the rule.
Scoring
Pass: Because a null return from get would be ambiguous between absent and present-with-null, and in a concurrent map you cannot resolve that with a follow-up containsKey — the entry can change between the calls.
Fail: Says it is an arbitrary API decision.
7. “Can you use size() to enforce a capacity?”
Testing: Two separate reasons it fails.
Scoring
Pass: No, twice over. It is an estimate from striped counters and may be stale; and even an exact size would not help, because check-then-act lets many threads pass together. A whole-map invariant needs a lock.
Fail: Only mentions the estimate, or thinks it is exact.
8. “What happens if you iterate while another thread writes?”
Testing: Weakly consistent versus fail-fast.
Scoring
Pass: Nothing throws. The iterator is weakly consistent — it reflects the map at some point at or after creation and may or may not show concurrent changes. HashMap is the one that throws ConcurrentModificationException, and even that is best-effort.
Fail: Expects a ConcurrentModificationException.
9. “`map.computeIfAbsent(k, x -> new ArrayList<>()).add(item)` — safe?”
Testing: Container versus contents.
Scoring
Pass: No. Exactly one list is created, then add runs outside the lock on a plain ArrayList from several threads, corrupting it. A thread-safe map says nothing about what you store in it.
Fail: Says it is safe because computeIfAbsent is atomic.