CopyOnWriteArrayList适用于读多写少场景,读操作无锁、写操作通过复制数组实现线程安全;迭代器为快照式,遍历时不受并发修改影响,但不反映实时变更。

CopyOnWriteArrayList 是 Java 并发包(java.util.concurrent)中专为“读多写少”场景设计的线程安全列表。它的核心思想是:**读操作完全无锁,写操作通过复制底层数组实现线程安全**。这意味着每次增删元素时,都会创建新数组、复制旧数据、更新引用——代价由写承担,读则零开销。
为什么适合读多写少?
读操作(get、size、iterator)直接访问当前数组快照,不加锁、不阻塞;写操作(add、remove、set)需加锁、复制整个数组。因此:
- 读频次远高于写时,整体性能显著优于
synchronized ArrayList或Vector - 写操作频繁时,内存占用高、GC 压力大、响应延迟明显,应避免使用
- 迭代器是快照式的,遍历时即使列表被修改,也不会抛
ConcurrentModificationException,也不会反映新增/删除的元素
典型适用场景举例
常见于配置监听器、事件订阅者管理、白名单/黑名单缓存等场景:
- 服务注册中心维护活跃客户端列表,查询频繁,上线/下线较少
- GUI 应用中监听器集合,事件触发(读)远多于添加/移除监听器(写)
- 日志级别开关的观察者列表,运行时极少变更,但每条日志都要遍历判断是否输出
基本用法与注意事项
用法和普通 ArrayList 类似,但需注意语义差异:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- 构造:直接实例化即可,支持传入初始集合
new CopyOnWriteArrayList(originalList) - 写操作会立即生效,但仅对后续读可见;正在执行的迭代器仍看到旧快照
- 不支持
listIterator()的双向修改,也不支持subList()的结构修改 - 批量操作如
addAll也是原子的,但会一次性复制全部元素,慎用于大集合 - 若需弱一致性 + 更低写开销,可考虑
ConcurrentHashMap配合Collections.unmodifiableList等组合方案
一个轻量示例
模拟监听器通知场景:
CopyOnWriteArrayList<Runnable> listeners = new CopyOnWriteArrayList<>();
// 注册监听器(写少)
listeners.add(() -> System.out.println("A"));
listeners.add(() -> System.out.println("B"));
// 通知所有监听器(读多)
for (Runnable r : listeners) {
r.run(); // 安全遍历,即使其他线程正在 add/remove
}
此时若有线程调用 listeners.add(...),不会影响当前 for-each 的执行结果,也不会导致异常。

















