ConcurrentHashMap

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • ConcurrentHashMap is a highly efficient, thread-safe implementation of Map.
  • Unlike Hashtable, it does not lock the entire map. It locks only specific portions (buckets/segments).
  • Does not allow null keys or null values.
  • Preferred choice for highly concurrent applications.

Concept

When multiple threads read and write to a map, Hashtable locks the whole object, crushing performance. ConcurrentHashMap uses a technique called Lock Striping (or bucket-level locking in Java 8+).

If Thread A is writing to bucket index 3, it only locks bucket 3. Thread B can simultaneously write to bucket 15 without any blocking. Furthermore, read operations generally do not block at all! Multiple threads can read from the map concurrently without acquiring locks.

Examples

import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        Map<String, Integer> map = new ConcurrentHashMap<>();
        
        map.put("A", 1);
        map.put("B", 2);
        
        // Nulls are not allowed! Throws NullPointerException
        // map.put(null, 3); 
        
        // Atomic operations specific to concurrent maps
        // Only puts "C" if "C" does not already exist
        map.putIfAbsent("C", 3); 
        
        // Safely compute a new value atomically
        map.compute("A", (key, val) -> val == null ? 1 : val + 10);
        
        System.out.println(map.get("A")); // 11
    }
}

Interview Questions

Q: How did the internal locking mechanism of ConcurrentHashMap change in Java 8?
A: Prior to Java 8, ConcurrentHashMap used “Segment-based” locking (usually 16 segments). Threads only locked the specific segment they were writing to.
In Java 8, Segments were removed. It now uses the same bucket-array structure as a regular HashMap, and uses CAS (Compare-And-Swap) operations and synchronizes on the first node of a specific bucket. This provides even finer-grained locking and better performance.

Q: Why doesn’t ConcurrentHashMap allow null keys or values?
A: Because of concurrency ambiguities. If map.get(key) returns null, does it mean the key doesn’t exist, or does it mean another thread explicitly set the value to null a millisecond ago? In a single-threaded HashMap, you can check map.containsKey(key) to figure it out. In a concurrent environment, the map could change between calling get() and containsKey(). Disallowing null entirely removes this ambiguity.