Skip to main content
  1. Java Concurrency (java.util.concurrent)/

CopyOnWriteArrayList

2 mins

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 #

View Source on GitHub

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 volatile reference to ensure visibility to all reading threads.
  • Copy-On-Write: When you call add(), set(), or remove(), the list acquires a lock, makes a copy of the entire array, applies the change to the copy, and then replaces the volatile reference 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 CopyOnWriteArrayList allows 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.