Skip to content

# Part 8 — Concurrent Collections Deep Dive (Senior Java)

This is one of the highest-frequency topics in senior Java interviews.

Typical questions:

  • Why is HashMap not thread-safe?
  • Why not simply use Collections.synchronizedMap()?
  • How does ConcurrentHashMap work internally?
  • What changed from Java 7 to Java 8?
  • What is CAS?
  • When should you use CopyOnWriteArrayList?

1. Why Normal Collections Fail in Multithreading

Consider:

Map<Integer, String> map = new HashMap<>();

Thread 1:

map.put(1, "A");

Thread 2:

map.put(2, "B");

Both threads modify the same internal structure simultaneously.

Possible consequences:

  • Lost updates
  • Corrupted buckets
  • Inconsistent reads
  • Resize corruption (especially problematic in older JDKs)

HashMap provides no synchronization.


2. Race Condition

Example:

Initial value:

count = 0

Thread 1:

Read 0

Thread 2:

Read 0

Thread 1:

Write 1

Thread 2:

Write 1

Expected:

2

Actual:

1

This is a race condition.


3. Collections.synchronizedMap()

Java provides:

Map<Integer, String> map =
    Collections.synchronizedMap(new HashMap<>());

Internally:

synchronized (mutex) {
    map.put(key, value);
}

Only one thread can access the map at a time.


Problem

Suppose:

100 threads

Thread 1 → waiting

Thread 2 → waiting

Thread 3 → waiting

Only one proceeds.

Performance suffers significantly under contention.


4. ConcurrentHashMap

Designed specifically for concurrent access.

Example:

ConcurrentHashMap<Integer, String> map =
    new ConcurrentHashMap<>();

Characteristics:

  • Thread-safe
  • High throughput
  • No global lock
  • Excellent scalability

5. Java 7 Implementation

Interview question.

Java 7 used segment locking.

Structure:

ConcurrentHashMap

↓

Segment[]

↓

HashEntry[]

Each segment had its own lock.

Example:

Segment 1 → Locked

Segment 2 → Free

Segment 3 → Free

Threads working in different segments proceeded concurrently.


Drawback

Too many segments increased memory overhead and added implementation complexity.


6. Java 8 Implementation

Java 8 removed segments.

Current structure:

ConcurrentHashMap

↓

Node[]

Similar to HashMap, but with sophisticated concurrency control.

Synchronization occurs per bucket when necessary.


7. CAS (Compare-And-Set)

One of the most important interview concepts.

CAS is an atomic CPU-supported operation.

Concept:

Current value = A

Expected = A

New value = B

If the current value is still A:

Replace with B

Otherwise:

Retry

No traditional lock is required.


Example

Thread 1:

Expected = 10

Current:

10

CAS:

10 → 20

Success.


Thread 2:

Expected:

10

Current:

20

CAS fails.

Thread 2 retries.


8. Why CAS?

Traditional locking:

Acquire lock

↓

Modify

↓

Release lock

CAS:

Try

↓

Success?

↓

Done

↓

Else retry

Advantages:

  • Less blocking
  • Better scalability
  • Higher throughput under light to moderate contention

9. put() in ConcurrentHashMap

Simplified flow:

hash

↓

bucket

↓

Empty?

↓

CAS insert

If the bucket is already occupied:

Lock bucket

↓

Modify linked list/tree

↓

Unlock

Only the affected bucket is synchronized.

Other buckets remain accessible.


10. Read Operations

Interview favorite.

get() is typically lock-free.

map.get(key);

Readers generally do not block each other or writers (subject to memory visibility guarantees provided by the implementation).

This is a major reason ConcurrentHashMap performs well.


11. Null Keys and Values

Unlike HashMap:

ConcurrentHashMap

does not allow:

null key

null value

Reason:

map.get(key)

Returning null must unambiguously mean:

  • Key absent

There should be no confusion with:

key -> null

12. Resize

Concurrent resizing is coordinated so that multiple threads can assist with transferring buckets.

This avoids one thread becoming a bottleneck.

The implementation is considerably more complex than HashMap.


13. Treeification

Exactly like HashMap:

Linked List

Red-Black Tree

when:

  • Bucket size ≥ 8
  • Table capacity ≥ 64

14. Time Complexity

Operation Average
put O(1)
get O(1)
remove O(1)

Worst-case bucket operations remain O(log n) after treeification.


15. CopyOnWriteArrayList

Another favorite interview topic.

Designed for:

  • Many readers
  • Few writers

Example:

CopyOnWriteArrayList<String> list =
    new CopyOnWriteArrayList<>();

Write Operation

Suppose:

[A B C]

Add:

D

Internally:

Copy array

↓

[A B C D]

↓

Replace reference

Readers continue using the old array until the new one becomes visible.


Advantages

  • Iteration requires no locking.
  • No ConcurrentModificationException.
  • Excellent for read-heavy workloads.

Disadvantages

Every write copies the entire array.

Writing complexity:

O(n)

16. When to Use CopyOnWriteArrayList

Good:

  • Configuration data
  • Listener lists
  • Plugin registries
  • Feature flags

Bad:

  • Frequent insertions
  • Large mutable lists

17. ConcurrentLinkedQueue

Implementation:

  • Lock-free
  • CAS-based
  • FIFO

Suitable for:

  • High-concurrency message passing
  • Task queues

18. BlockingQueue

Used in producer-consumer systems.

Example:

BlockingQueue<String> queue =
    new LinkedBlockingQueue<>();

Producer:

queue.put(task);

Consumer:

queue.take();

If empty:

Consumer waits.

19. ConcurrentSkipListMap

Thread-safe alternative to TreeMap.

Characteristics:

  • Sorted
  • Concurrent
  • O(log n)

Internally:

Skip List

instead of a Red-Black Tree.


20. Skip List

Conceptually:

Level 3

↓

Level 2

↓

Level 1

↓

Sorted List

Search skips large portions of the data.

Average:

O(log n)

21. WeakHashMap

Interview favorite.

Keys are stored using weak references.

If no strong reference to a key exists:

GC

↓

Entry removed automatically

Useful for:

  • Caches
  • Metadata associated with objects

22. IdentityHashMap

Normal HashMap:

equals()

IdentityHashMap:

==

Example:

String a = new String("Java");
String b = new String("Java");

HashMap:

1 key

IdentityHashMap:

2 keys

because a != b by reference.


23. EnumMap

Optimized for enum keys.

Example:

enum Status {
    NEW,
    RUNNING,
    DONE
}

EnumMap<Status, String> map =
    new EnumMap<>(Status.class);

Advantages:

  • Very fast
  • Memory efficient
  • Array-backed internally

24. Choosing the Right Concurrent Collection

Requirement Collection
Thread-safe map ConcurrentHashMap
Read-heavy list CopyOnWriteArrayList
FIFO concurrent queue ConcurrentLinkedQueue
Producer-consumer BlockingQueue
Sorted concurrent map ConcurrentSkipListMap
Weak-reference cache WeakHashMap
Enum keys EnumMap

Common Interview Questions

Q1. Why is HashMap not thread-safe?

Because concurrent modifications can corrupt its internal state and it performs no synchronization.


Q2. Why not always use Collections.synchronizedMap()?

It uses a single lock, reducing concurrency and scalability.


Q3. Difference between Java 7 and Java 8 ConcurrentHashMap?

Java 7 Java 8
Segment locking Bucket-level synchronization + CAS
More memory overhead Lower overhead
More complex structure Simpler Node[]-based design

Q4. Why is get() fast?

Reads are generally lock-free.


Q5. Why are nulls not allowed?

To avoid ambiguity between:

  • Key not present
  • Key mapped to null

Q6. When should you use CopyOnWriteArrayList?

When reads vastly outnumber writes.


Q7. What is CAS?

An atomic compare-and-update operation that reduces the need for locks.


Q8. Which concurrent map maintains sorted order?

ConcurrentSkipListMap

Q9. Difference between TreeMap and ConcurrentSkipListMap?

TreeMap ConcurrentSkipListMap
Not thread-safe Thread-safe
Red-Black Tree Skip List
O(log n) O(log n)

Q10. What would you use for a cache?

It depends:

  • Simple concurrent cache → ConcurrentHashMap
  • Cache requiring automatic eviction of entries whose keys are no longer referenced → WeakHashMap
  • Production caches with expiration, size limits, and statistics → libraries such as Caffeine (commonly used in modern Java applications)

Senior Interview Scenario

Question:

Your application has:

  • 500 reader threads
  • 5 writer threads

Should you use:

  • Collections.synchronizedMap()
  • ConcurrentHashMap

Expected Answer:

ConcurrentHashMap.

Reason:

  • Readers generally proceed without blocking.
  • Writes synchronize only where necessary.
  • Throughput scales much better than a single global lock.

Key Takeaways

  • HashMap is not thread-safe.
  • ConcurrentHashMap is the standard concurrent map implementation.
  • Java 8 replaced segment locking with bucket-level synchronization and CAS.
  • CAS enables many operations without traditional locking.
  • CopyOnWriteArrayList is ideal for read-heavy workloads.
  • BlockingQueue is fundamental for producer-consumer designs.
  • ConcurrentSkipListMap provides thread-safe sorted maps.
  • WeakHashMap, IdentityHashMap, and EnumMap solve specialized problems.

Next: Part 9 — Iterators Deep Dive

We'll cover:

  • Iterator
  • ListIterator
  • Enumeration
  • Fail-fast vs fail-safe iterators
  • modCount
  • ConcurrentModificationException
  • Safe element removal during iteration
  • Internal implementation and interview questions