114. CopyOnWriteArrayList vs Collections.synchronizedList
CopyOnWriteArrayList optimizes lock-free reads by cloning the backing array on every write, while Collections.synchronizedList serializes all operations behind a single mutual-exclusion lock.
Explanation
When multiple threads read and write a shared List, developers must ensure thread safety. The JDK offers two standard solutions with drastically different performance characteristics:
1. Collections.synchronizedList(list): Wraps any standard list in a synchronization wrapper. Every method (get, add, remove, size) acquires a single shared intrinsic lock (this or mutex). Reads block other reads, creating severe lock contention under high concurrency. Furthermore, iterating over a synchronized list still requires manual synchronization on the list to avoid ConcurrentModificationException. 2. CopyOnWriteArrayList: All read operations (get, iterator, contains) are 100% lock-free and execute directly on the current volatile array reference without blocking. Whenever a mutation occurs (add, set, remove), the entire backing array is cloned, modified, and swapped atomically. - Iterators create a snapshot of the array at creation time and never throw ConcurrentModificationException, but they do not reflect subsequent writes and do not support iterator.remove(). - Ideal use case: Read-heavy, write-rare structures like event listener registries or whitelist configurations. - Trap: If writes are frequent or lists are large, the array copying causes severe memory churn and GC pressure.
Example
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteDemo {
public static void main(String[] args) {
CopyOnWriteArrayList<String> listeners = new CopyOnWriteArrayList<>();
listeners.add("OnLogin");
listeners.add("OnLogout");
// Safe iteration during concurrent modification:
Iterator<String> iterator = listeners.iterator();
// Mutate list while iterator is active!
listeners.add("OnPasswordReset");
System.out.println("Snapshot iterator output (does not see OnPasswordReset):");
while (iterator.hasNext()) {
System.out.println(" Listener: " + iterator.next());
}
System.out.println("Current list contents:");
System.out.println(" " + listeners);
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html โ CopyOnWriteArrayList API
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Collections.html#synchronizedList(java.util.List) โ Collections.synchronizedList API