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...
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:
- Thread A calls
get(0)→ acquires themutexmonitor - Thread B calls
get(1)→ blocks onsynchronized, waits - Thread A finishes → releases the monitor
- 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
- Iteration → synchronized block
- Do not expose the original
- ConcurrentHashMap is preferable
- mutex = this by default
- 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
mutexobject (by defaultthis) - 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 defaultthis, 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]]