Skip to main content

5.6 Concurrent & Specialized Collections: ConcurrentHashMap & Immutable Collections

← Back to Chapter 5: Collections Framework

Standard collections (HashMap, ArrayList) are not thread-safe. Accessing them concurrently without synchronization causes race conditions, infinite loops during rehashing, or ConcurrentModificationException.


1. ConcurrentHashMap: Lock-Free Reads & Fine-Grained Locking​

Unlike Hashtable or Collections.synchronizedMap() (which block every thread with a single global object lock), Java 8+ ConcurrentHashMap:

  1. Reads (get()): 100% lock-free using volatile read semantics.
  2. Writes (put()):
    • If the target bucket is empty: Inserts node lock-free using CAS (Compare-And-Swap).
    • If bucket has collisions: Locks only that single bucket head node using synchronized(node). Other threads operating on different buckets proceed in parallel!
ConcurrentMap<String, Long> metrics = new ConcurrentHashMap<>();
// Atomic thread-safe update without external synchronized blocks
metrics.compute("active_users", (k, v) -> (v == null) ? 1L : v + 1L);

2. CopyOnWriteArrayList: Thread-Safe Read-Heavy Lists​

  • Every mutating operation (add, set, remove) allocates a complete fresh copy of the internal underlying array.
  • Iterators take a snapshot reference to the array at the moment iteration begins:
    • Iteration never throws ConcurrentModificationException.
    • Iteration does not require synchronization.
  • Ideal for: Event listeners, observer registries, and configurations updated infrequently but read millions of times.

3. Java 9+ Immutable Factory Methods​

List<String> immutableList = List.of("A", "B", "C");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("key1", 100, "key2", 200);
  • Space-Efficient: Custom internal compact implementations (e.g., List12, ListN) requiring fewer object headers than ArrayList.
  • Truly Immutable: Calling mutating methods (add(), put()) throws UnsupportedOperationException.
  • Null-Hostile: Rejects null keys and elements with NullPointerException by design.