CopyOnWriteArraySet 是基于写时复制的线程安全 Set,适合读多写少场景:读操作无锁高效,写操作复制数组开销大;不支持 null,迭代器只读且基于快照,不保证实时一致性。

CopyOnWriteArraySet 是 Java 并发包(java.util.concurrent)中为读多写少场景设计的线程安全 Set 实现,底层基于 CopyOnWriteArrayList,通过“写时复制”(Copy-on-Write)机制保证线程安全——每次写操作(如 add、remove)都会创建新数组并替换原引用,而读操作(如 contains、iterator)全程无锁、直接访问当前数组快照。
为什么适合读多写少?
读操作不加锁、不阻塞,性能接近普通 HashSet;写操作虽需复制整个数组(时间复杂度 O(n)),但因写操作极少,整体开销可控。若写操作频繁,会导致大量数组复制和 GC 压力,此时应改用 ConcurrentHashMap.newKeySet() 或加锁保护的 HashSet。
基本用法与线程安全保障
直接实例化即可使用,所有 public 方法天然线程安全:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
set.add("a"); // 线程安全
set.remove("b"); // 线程安全
boolean exists = set.contains("a"); // 无锁、快照语义
for (String s : set) { ... } // 迭代基于当前快照,不抛 ConcurrentModificationException
- 迭代器是只读的:调用
iterator.remove()会抛UnsupportedOperationException - 写操作期间,正在执行的读操作仍看到旧快照,因此不保证实时一致性(例如 A 线程刚
add,B 线程立刻contains可能返回false) - 元素去重依赖
equals()和hashCode(),和普通Set行为一致
典型适用场景示例
适用于状态监听器注册、配置白名单、缓存键集合等“初始化后极少变更、运行时高频查询”的场景:
立即学习“Java免费学习笔记(深入)”;
- 事件监听器管理:
CopyOnWriteArraySet<Listener>存储监听器,遍历时无需担心并发修改 - 动态白名单:
CopyOnWriteArraySet<String>存用户 ID,校验请求时高频调用contains - 避免手动同步:替代
Collections.synchronizedSet(new HashSet<>()),省去外部synchronized块
注意事项与常见误区
-
不要用于大容量集合:假设集合有 10 万元素,每次
add都要复制 10 万个引用,内存和 CPU 开销显著 -
不支持 null 元素:添加
null会抛NullPointerException -
批量操作非原子:如
addAll(Collection)是逐个添加,中间可能被其他线程读到部分结果;如需强一致性,应封装为单次写操作或换用其他方案 -
内存可见性已内置:内部使用
volatile数组引用,无需额外volatile或synchronized

















