Why ConcurrentHashMap cannot have a lock for each bucket?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
ConcurrentHashMap could, in theory, be designed with one lock per bucket, but that is not the design Java chose as its general strategy. The real question is not "is it impossible," but "why is per-bucket locking not the preferred overall design?" The answer comes down to memory cost, resizing complexity, coordination across operations, and the fact that modern implementations use more nuanced techniques than a simple fixed lock grid.
Bucket Locks Are Possible in Principle
It is important to correct the premise first: a concurrent hash map can be built with one lock per bucket. That is not forbidden by computer science. The issue is that it is often a poor tradeoff for a general-purpose standard-library map.
If the table has many buckets, then a lock-per-bucket design means:
- many lock objects
- more memory overhead
- more work when resizing
- more bookkeeping during operations that span multiple buckets
So the design cost rises quickly.
Why a Fixed Lock Per Bucket Is Awkward
Hash tables resize. When the number of buckets changes, a rigid one-lock-per-bucket strategy becomes awkward because the locking structure must also change in a way that stays thread-safe during rehashing.
That is not impossible, but it complicates the implementation. A standard library collection has to balance:
- throughput
- memory efficiency
- maintainability
- correctness during resize and traversal
Per-bucket locks tend to make that balance harder rather than easier.
Older and Newer ConcurrentHashMap Designs
Older Java implementations used segmented locking rather than a lock on every bucket. That reduced contention without allocating a lock for each individual bucket.
Modern Java implementations are even more fine-grained and rely on a mix of techniques such as:
- CAS-style updates for some operations
- bin-level synchronization when needed
- special handling for tree bins and resize states
So the real story is not "no lock near a bucket ever exists." It is that ConcurrentHashMap is optimized around a hybrid design rather than a simple permanent one-lock-per-bucket scheme.
Reads Are a Big Part of the Story
One reason ConcurrentHashMap performs well is that many reads can proceed with minimal blocking. A naive lock-per-bucket design can add coordination costs that are unnecessary for read-heavy workloads.
The map is built for the common case where:
- reads are frequent
- writes are localized
- full-table operations must still remain safe
A coarse design wastes concurrency. A per-bucket lock design can waste memory and complicate resizing. The actual implementation tries to sit in the productive middle.
Operations Are Not Always Bucket-Local
Another reason pure bucket locking is not enough conceptually is that some operations touch more than one bucket or depend on table-wide state:
- resizing
- size estimation
- traversal and bulk operations
- treeification of bins
If every operation were strictly isolated to one static bucket forever, per-bucket locks would be easier to justify. Real concurrent maps are more complicated than that.
Common Pitfalls
The biggest pitfall is asking the question as though per-bucket locking were impossible. It is possible; it is just not the chosen general strategy for Java's ConcurrentHashMap.
Another common mistake is thinking only about write contention and ignoring memory overhead, resize mechanics, and read scalability. Lock design is a system tradeoff, not just a concurrency slogan.
Developers also sometimes reason from very old ConcurrentHashMap implementations as though they describe the current internals exactly. The implementation strategy evolved substantially over time.
Summary
- A concurrent hash map can have one lock per bucket in principle.
- '
ConcurrentHashMapavoids a simple fixed bucket-lock design because of tradeoffs in memory, resizing, and coordination complexity.' - Older versions used segmented locking; newer ones use a more hybrid fine-grained approach.
- The design is optimized for real workloads, especially read-heavy ones, not for a simplistic locking model.
- The better question is why per-bucket locking is not the best overall tradeoff, not whether it is theoretically possible.
Related reading
- Why Do I have to worry about Thread Safety in CPython?
- Why do we need middleware for async flow in Redux?
- Why do we need middleware for async flow in Redux?
- Why does a condition variable need a lock and therefore also a mutex
- Why consumer hangs while consuming messages from Kafka on DC/OS using Client API for Java?
- Why do comparisons with Integer.valueOfString give different results for 127 and 128?
- Why does a System.Timers.Timer survive GC but not System.Threading.Timer?
- Why does an async single task run faster than a normal single task?

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.