Question 22 · Section 4

How to get a synchronized collection?

A synchronized collection is a wrapper (decorator) around a regular collection that wraps every method in a synchronized block. This guarantees that only one thread at a time ca...

Language versions: English Russian Ukrainian

A synchronized collection is a wrapper (decorator) around a regular collection that wraps every method in a synchronized block. This guarantees that only one thread at a time can call any method of the collection.

🟢 Junior Level

Using Collections.synchronizedX:

List<String> list = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> map = Collections.synchronizedMap(new HashMap<>());
Set<String> set = Collections.synchronizedSet(new HashSet<>());

IMPORTANT: iteration requires synchronized!

// ❌ Incorrect
for (String s : syncList) { ... }

// ✅ Correct
synchronized (syncList) {
    for (String s : syncList) { ... }
}

🟡 Middle Level

Factory methods

Collections.synchronizedList(list)
Collections.synchronizedMap(map)
Collections.synchronizedSet(set)
Collections.synchronizedNavigableMap(navigableMap)  // Java 8+

Mechanics: Decorator pattern

// Internally:
class SynchronizedList<E> implements List<E> {
    final List<E> list;
    final Object mutex;  // = this by default

    public synchronized E get(int index) {
        return list.get(index);  // synchronized on mutex
    }
}

What happens under concurrent access:

  1. Thread A calls get(0) → acquires the mutex monitor
  2. Thread B calls get(1) → blocks on synchronized, waits
  3. Thread A finishes → releases the monitor
  4. Thread B gets access

Comparison with alternatives

Method When
Collections.synchronizedX Full lock needed
ConcurrentHashMap High load, frequent writes
CopyOnWriteArrayList Listener lists
Vector/Hashtable NEVER (legacy)

Typical mistakes

// 1. Forgotten synchronized on iteration
for (var e : syncList) { ... }  // CME!

// 2. Exposing the original
List original = new ArrayList<>();
List sync = Collections.synchronizedList(original);
original.add("x");  // Thread-safety violated!

// 3. Double synchronization
synchronized (syncList) {
    syncList.add(e);  // Internal + external synchronized
}

🔴 Senior Level

Mutex object

// By default mutex (mutual exclusion — lock object for synchronized) = this (the wrapper)
// → All synchronized methods block each other
// backing collection — the original collection wrapped by the synchronized wrapper

// You can (through reflection) set a custom mutex
// → But JDK API doesn't support this directly

Production Experience

Why ConcurrentHashMap is better:

synchronizedMap:
  → 1 lock for everything
  → Read blocks read

ConcurrentHashMap:
  → Lock-free reads
  → CAS for writes
  → Granular locks per bucket

Best Practices

  1. Iteration → synchronized block
  2. Do not expose the original
  3. ConcurrentHashMap is preferable
  4. mutex = this by default
  5. Avoid double synchronization

Summary for Senior

  • Decorator pattern → synchronized on every method
  • Iteration → manual synchronized block
  • mutex = this → full locking
  • ConcurrentHashMap > synchronizedMap
  • Do not expose the backing collection (the original being wrapped)

🎯 Interview Cheat Sheet

Must know:

  • Collections.synchronizedList/Set/Map — factory wrapper methods (Decorator pattern)
  • Each synchronizes on a single mutex object (by default this)
  • Iteration always requires a synchronized(list) { ... } block
  • The original collection remains accessible — modifying it through the original breaks thread-safety
  • Double synchronization (synchronized(syncList) { syncList.add(e); }) — extra overhead
  • Alternatives: ConcurrentHashMap (high load), CopyOnWriteArrayList (listener lists)
  • Vector/Hashtable — legacy, NEVER in new code

Frequent follow-up questions:

  • What is mutex in synchronized collections? — The lock object for synchronized; by default this, all methods block each other.
  • Why does iterating over a synchronizedList without a synchronized block lead to CME? — The iterator calls hasNext/next separately; between calls, another thread may modify the collection.
  • How does Collections.synchronizedList differ from ConcurrentHashMap? — The former — one lock for everything; the latter — lock-free reads + granular locks.
  • What is a backing collection? — The original collection wrapped by the synchronized wrapper; accessing it bypassing the wrapper breaks thread-safety.

Red flags (DO NOT say):

  • “You can modify the original collection without consequences” — this breaks thread-safety
  • “synchronizedList guarantees atomicity of compound operations” — no, an external synchronized is needed
  • “Iterator.remove() works without synchronized for synchronizedList” — iteration always requires manual locking
  • “Vector is a modern alternative” — it’s legacy with coarse-grained locking

Related topics:

  • [[21. When to use synchronized collections]]
  • [[23. What is Collections.unmodifiableList()]]
  • [[25. What is the difference between Iterator and ListIterator]]