How does ConcurrentHashMap achieve thread safety without locking the whole map?

9 minadvancedconcurrenthashmapcasinternals

Quick Answer

Modern ConcurrentHashMap (Java 8+) synchronizes only at the level of individual bins (buckets), locking just the head node of a bucket being modified rather than the whole table, and uses CAS (compare-and-swap) operations for many updates to avoid locking entirely where possible. This lets unrelated keys in different buckets be read and written concurrently by different threads with minimal contention, unlike Hashtable's single lock covering the entire map.

Detailed Answer

Older Hashtable/synchronizedMap wrap every operation in a single lock covering the whole map — only one thread can touch the map at all, even for unrelated keys.

ConcurrentHashMap (redesigned in Java 8) instead achieves much finer-grained concurrency:

  • Per-bin (bucket) synchronization: updates that need to modify a bucket's linked list/tree only synchronize on that specific bucket's head node, not the whole table. Two threads writing to different buckets don't block each other at all.
  • CAS (compare-and-swap) for simple cases: for many operations — like inserting into an empty bucket — ConcurrentHashMap uses lock-free CAS operations (Unsafe/VarHandle compare-and-set) instead of acquiring a lock at all, since a single-element bucket insert can be done atomically without synchronization.
  • Reads are (mostly) lock-free: get() doesn't lock at all — it relies on volatile reads of bucket references and node values, so reads never block on writes and writes never block on reads (though a read might occasionally see a slightly stale view during a resize, which is acceptable for its "weakly consistent" iteration guarantee).
  • Incremental resizing: when the table needs to grow, multiple threads can cooperatively help move nodes from the old table to the new one in the background, rather than one thread performing a full stop-the-world rehash.

The net effect: contention is limited to threads that happen to hit the same bucket at the same time — for a well-sized, well-distributed map, real contention is rare, giving throughput far closer to an unsynchronized HashMap than to a globally-locked Hashtable.