CopyOnWriteArrayList
CopyOnWriteArrayList is a thread-safe implementation of the List interface that provides a unique solution to the concurrency problem: every mutative operation creates a complete copy of the underlying array.
Source Code #
The “Snapshot” Iterator #
One of the most important properties of CopyOnWriteArrayList is its iterator. When you call iterator(), it captures a reference to the current array at that exact moment. This is a snapshot of the data.
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0);
}
Because the underlying array never changes (instead, a new one is created for mutations), the iterator will never throw a ConcurrentModificationException. This makes it safe to traverse the list even if another thread is adding or removing elements.
Implementation Mechanism #
- Volatile Array Reference: The underlying array is stored in a
volatilereference to ensure visibility to all reading threads. - Copy-On-Write: When you call
add(),set(), orremove(), the list acquires a lock, makes a copy of the entire array, applies the change to the copy, and then replaces thevolatilereference with the new array.
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements); // Replaces the volatile reference
return true;
} finally {
lock.unlock();
}
}
Canonical Usage #
When to use: Use CopyOnWriteArrayList when reads vastly outnumber writes and when you want to avoid synchronizing during traversal. It is ideal for listener lists or small configuration lists.
Common Patterns:
- Event Listeners: A system where listeners are added or removed infrequently but are notified often. Using
CopyOnWriteArrayListallows the notification loop to run without any locking. - Read-Only Cache Views: Providing a thread-safe view of a small dataset that is updated only occasionally.
private final List<EventListener> listeners = new CopyOnWriteArrayList<>();
// Notification is thread-safe and lock-free!
public void fireEvent(Event e) {
for (EventListener l : listeners) {
l.onEvent(e);
}
}
Performance Trade-offs #
- Pros: Wait-free reads. Snapshot iterators never throw
ConcurrentModificationException. Very simple to use. - Cons: Extremely expensive writes (linear time
O(n)to copy the whole list). High memory pressure if writes are frequent.