What is CopyOnWriteArrayList, and when should you use it?

CopyOnWriteArrayList is a thread-safe List where every write (add, set, remove) creates a new copy of the underlying array. Reads never lock, and iterators work on a snapshot, so they never throw ConcurrentModificationException. It is excellent when reads vastly outnumber writes, such as lists of listeners or configuration, and poor when writes are frequent.

Key Points: • Reads (get, iteration) are lock-free and fast. • Each write copies the whole array, which is O(n). Frequent writes to a large list are expensive. • Iterators see the list as it was when they were created. iterator.remove() is not supported. • Typical uses: event listener lists, observer registrations, rarely changing whitelists or routing tables. • For write-heavy concurrent lists, use Collections.synchronizedList() with careful locking, or a ConcurrentLinkedQueue if you only need queue operations. • CopyOnWriteArraySet is the Set version.

Code Example:

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;

public class CopyOnWriteDemo {

    static final List<Consumer<String>> listeners = new CopyOnWriteArrayList<>();

    static void publish(String event) {
        for (Consumer<String> l : listeners) {          // safe even if a listener unsubscribes
            l.accept(event);
        }
    }

    public static void main(String[] args) {
        Consumer<String> logger = e -> System.out.println("Logger: " + e);
        listeners.add(logger);
        listeners.add(new Consumer<>() {
            public void accept(String e) {
                System.out.println("One-time listener: " + e);
                listeners.remove(this);                 // modifies the list during iteration
            }
        });

        publish("order-created");
        publish("order-paid");
        System.out.println("Listeners left: " + listeners.size());
    }
}

Output:

Logger: order-created One-time listener: order-created Logger: order-paid Listeners left: 1

Good to Know: With a plain ArrayList, the one-time listener removing itself during publish() would throw ConcurrentModificationException. This "listener removes itself" situation is exactly why event systems use CopyOnWriteArrayList.

Interview Tip: A concise interview answer is:

"CopyOnWriteArrayList is a thread-safe list that copies its whole array on every write, so reads and iteration need no locking and iterators work on a snapshot without ever throwing ConcurrentModificationException. I use it for read-mostly data like listener lists, and avoid it when writes are frequent, because each write is O(n)."

Previous question: What are EnumMap and EnumSet, and why are they faster than HashMap and HashSet?

Next question: What is a BlockingQueue, and how do you use it for the producer–consumer problem?

More Java Collections interview questions

All Java Collections questions