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?