Concurrent Collections

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

TL;DR

  • Concurrent Collections (in java.util.concurrent) are thread-safe data structures optimized for high-performance multithreading.
  • They completely replace old, legacy synchronized collections (like Vector and Hashtable).
  • Key classes: ConcurrentHashMap, CopyOnWriteArrayList, BlockingQueue.

Concept

In the early days of Java, if you wanted a thread-safe list, you used Vector. Vector achieves thread-safety by putting a massive synchronized lock on every single method. If Thread A is reading item 1, Thread B is entirely blocked from reading item 2. This causes massive bottlenecks.

Modern Concurrent Collections use highly advanced, lock-free algorithms (like CAS) or fine-grained lock stripping to achieve thread safety without blocking the entire data structure.

The Big Three:

  1. ConcurrentHashMap: Divides the map into segments (or buckets in Java 8+). If Thread A writes to bucket 1, Thread B can simultaneously write to bucket 5 without waiting! Reads are entirely lock-free.
  2. CopyOnWriteArrayList: Every time you add() or remove(), it creates a full, brand-new copy of the underlying array. Writes are slow, but Reads are 100% lock-free and blazingly fast. Perfect for read-heavy lists (like event listeners).
  3. BlockingQueue: The backbone of producer-consumer patterns (used heavily in Thread Pools). put() blocks if the queue is full, take() blocks if the queue is empty.

Examples

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

public class ConcurrentCollectionsExample {
    public static void main(String[] args) {
        
        // High performance thread-safe map
        Map<String, Integer> map = new ConcurrentHashMap<>();
        
        // Thread 1
        new Thread(() -> {
            // putIfAbsent is completely atomic! No race conditions.
            map.putIfAbsent("apples", 10); 
        }).start();
        
        // Thread 2
        new Thread(() -> {
            // compute() is atomic. Safely updates the value.
            map.compute("apples", (key, val) -> (val == null) ? 1 : val + 5);
        }).start();
        
    }
}

Interview Questions

Q: What is the difference between Collections.synchronizedMap(new HashMap()) and ConcurrentHashMap?
A: Collections.synchronizedMap wraps a normal HashMap and puts a single, global synchronized lock over the entire object. Only one thread can perform any operation at a time, severely limiting throughput.
ConcurrentHashMap uses node-level locking (CAS operations on individual bins/buckets). Hundreds of threads can read and write to different parts of the map simultaneously without blocking each other. ConcurrentHashMap is vastly superior in performance.

Q: What is a Fail-Safe iterator versus a Fail-Fast iterator?
A: Standard collections (like ArrayList) are Fail-Fast. If you use a for-each loop to iterate over them, and another thread modifies the list mid-loop, it instantly throws a ConcurrentModificationException.
Concurrent collections (like CopyOnWriteArrayList or ConcurrentHashMap) provide Fail-Safe iterators. They iterate over a snapshot of the data. If another thread modifies the collection during the loop, it won’t crash, but the loop might not see the newly added data.