CopyOnWriteArrayList适用于读多写少场景:读操作无锁高效,写操作复制数组开销大;迭代器基于快照,不反映实时变更;适合监听器列表、配置白名单等,不适用强一致或高频写场景。

CopyOnWriteArrayList 本身就不加锁读取,高频读场景下天然无锁竞争,关键在于避免误用写操作。它通过“读写分离 + 写时复制”实现线程安全:所有读操作(get、iterator、size 等)直接访问内部数组,不加锁;写操作(add、remove、set 等)则先复制整个数组,修改副本后再原子替换引用。
读操作完全无锁,可放心高频调用
只要只做遍历、查元素、获取大小等读动作,无需任何同步措施:
-
list.get(i)直接数组访问,O(1),无同步开销 -
for (E e : list)使用快照迭代器,不阻塞写线程,也不被写操作影响 -
list.size()返回当前引用指向数组的长度,轻量且一致(注意:不是实时强一致性,但对多数监控、统计类读取已足够)
写操作代价高,必须严格控制频次和时机
每次写都会触发数组复制,时间复杂度 O(n),内存开销翻倍。高频写会严重拖慢性能,甚至引发频繁 GC:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 避免在循环内或高频事件回调中调用
add()或remove() - 批量写入优先用
addAll()替代多次单元素添加(仍会复制一次,而非多次) - 若需频繁增删,考虑换用
ConcurrentLinkedQueue、ConcurrentHashMap或读写锁保护的普通ArrayList
注意迭代器的“快照”语义与数据可见性
迭代器基于构造时刻的数组副本,无法看到后续写操作的结果:
立即学习“Java免费学习笔记(深入)”;
- 遍历时其他线程添加元素,本次迭代不会包含新元素
- 遍历时其他线程删除元素,本次迭代仍会返回已删除的旧值(只要它还在当前快照中)
- 若业务要求“读到最新状态”,CopyOnWriteArrayList 不适用,应改用
ConcurrentHashMap或加锁协调
适用场景要精准匹配
它适合“读多写少 + 写操作不敏感延迟 + 允许短暂数据滞后”的场景:
- 监听器列表(如 GUI 事件回调、Spring ApplicationListener)
- 配置项白名单、运行时开关集合(变更极少,读取极频繁)
- 监控指标采集中的标签集合、活跃连接 ID 列表等
- 不适用于实时排行榜、高频交易订单簿、需要强一致读写的共享状态

















