ConcurrentHashMap is thread-safe but still we need to be catious when working with it
Let’s break it down carefully.
1️⃣ ConcurrentHashMap is thread-safe — but only for individual operations
ConcurrentHashMap guarantees that single operations like get(), put(), remove() are atomic and thread-safe.
Example:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1);
System.out.println(map.get("key")); // thread-safe
✅ No race conditions if only one operation is performed.
2️⃣ Problem arises with compound operations
Compound operations = multiple steps that depend on each other.
Example: Check-then-act
if (!map.containsKey("key")) {
map.put("key", 1);
}
- Step 1: Check
containsKey - Step 2: Put if absent
❌ Problem: Two threads can do this at the same time:
- Thread A checks
containsKey("key")→ false - Thread B checks
containsKey("key")→ false - Both threads execute
put("key", 1)→ violates uniqueness or logic
Even though put() itself is thread-safe, the sequence of operations is not atomic.
3️⃣ Correct ways to handle this
a) Use putIfAbsent (atomic operation provided by CHM)
map.putIfAbsent("key", 1); // atomic
- This combines check + insert in one atomic operation.
- No race condition.
b) Use computeIfAbsent for initialization
map.computeIfAbsent("key", k -> expensiveCalculation());
- Thread-safe
- Only one thread will execute the lambda
- Other threads wait for the value to be available
c) Use external locks for more complex compound logic
synchronized(lock) {
if (!map.containsKey("key")) {
map.put("key", 1);
}
}
- Works, but usually slower than
putIfAbsentorcomputeIfAbsent
4️⃣ TL;DR for Interviews
“
ConcurrentHashMapensures thread safety for single operations (get,put,remove). But compound operations like check-then-act (containsKey+put) are not automatically atomic. To handle concurrency safely, useputIfAbsent,computeIfAbsent, or external synchronization.”
💡 Key idea: Thread-safe does not mean “all multi-step logic is safe.” It only guarantees each method call is atomic.