Internal Working: HashMap vs ConcurrentHashMap
Same hash-bucket idea, very different concurrency mechanics.
📌 Key Idea
HashMap optimizes for single-threaded performance with bucket chains/tree bins and periodic resize. ConcurrentHashMap uses fine-grained synchronization + CAS + lock-free reads to scale under concurrent access.Why It Matters
- Interview favorite — Common mid/senior Java question: explain bucketing, collisions, resize, and thread-safety trade-offs.
- Bug prevention — Knowing internals helps avoid race conditions, lost updates, and performance cliffs.
- API correctness — Choosing
computeIfAbsentvsget+putoften decides correctness under load.
Visual
🧱 HashMap internals (single-threaded view)
hash(key) -> index = (n - 1) & hash table[index] -> bucket bucket forms: null Node chain (linked list) TreeNode (red-black tree) when collisions high resize when size > threshold = capacity * loadFactor
🧵 ConcurrentHashMap internals (multi-threaded)
No global map lock for reads put() path: CAS insert into empty bin OR lock only that bin while mutating high collisions -> tree bin resize uses cooperative transfer by multiple threads atomic APIs: compute(), merge(), putIfAbsent()
Code Variations
1️⃣ HashMap bucket index formulajava
int h = key.hashCode();
int spread = h ^ (h >>> 16); // spread high bits
int idx = (table.length - 1) & spread;Power-of-two capacity makes bit-mask indexing fast.
2️⃣ Wrong concurrent pattern (race)java
Map<String, Integer> m = new HashMap<>();
// Thread A and B run simultaneously:
Integer v = m.get(k); // both read same old value
m.put(k, v + 1); // lost updateHashMap gives no atomicity for compound read-modify-write.3️⃣ Correct atomic update in ConcurrentHashMapjava
ConcurrentHashMap<String, LongAdder> counts = new ConcurrentHashMap<>();
counts.computeIfAbsent(key, k -> new LongAdder()).increment();Use atomic map methods +
LongAdder for high-contention counters.4️⃣ Treeification threshold intuitionjava
// Conceptual JDK behavior
if (binCount >= 8 && table.length >= 64) {
treeifyBin(); // linked-list bucket -> red-black tree
}Tree bins reduce worst-case lookup under heavy collisions.
HashMap vs ConcurrentHashMap internals
| Aspect | HashMap | ConcurrentHashMap |
|---|---|---|
| Thread safety | ❌ Not safe for concurrent mutation | ✅ Safe for concurrent access/mutation |
| Read path | Fast single-threaded | Mostly lock-free reads |
| Write path | No synchronization | CAS + per-bin locking |
| Collision handling | List -> tree bin | List/tree bin with synchronized bin mutation |
| Resize behavior | Single-thread resize/rehash | Concurrent cooperative transfer |
| Null support | Allows null key/value | Disallows null key/value |
Interview Q&A
Quick Cheat Sheet
HashMap coreArray of bins + list/tree collision structures.
CHM coreBin-level synchronization + CAS + lock-free reads.
Golden ruleNever mutate HashMap from multiple threads without external synchronization.
Counter pattern
ConcurrentHashMap + LongAdder.