copyonwritearrayset是基于copyonwritearraylist的轻量封装,通过手动查重+加锁保证唯一性;add需o(n)遍历检查,适合读多写少、元素少的场景。

CopyOnWriteArraySet 并不是独立实现的集合,而是对 CopyOnWriteArrayList 的一层轻量封装,它利用后者线程安全的“写时复制”特性,通过内部维护一个 CopyOnWriteArrayList 实例,并在所有操作中**手动保证元素唯一性**来模拟 Set 语义。
核心思路:用 List 存储 + 手动去重
由于 CopyOnWriteArrayList 本身不保证唯一性(允许重复),CopyOnWriteArraySet 在每次添加元素前,先遍历当前数组检查是否已存在该元素;只有确认不存在时,才调用底层 List 的 add() 方法。这个“查重 + 添加”的原子性由写操作的独占锁(ReentrantLock)保障。
关键方法如何实现
-
add(E e):先调用contains(e)检查是否存在(基于equals());若返回false,再调用al.add(e)(al是内部的CopyOnWriteArrayList)。整个过程加锁,避免并发添加相同元素。 -
contains(Object o):直接委托给底层CopyOnWriteArrayList.contains(o),本质是遍历当前快照数组做equals()判断。 -
remove(Object o):同样委托给al.remove(o),底层会创建新数组并跳过匹配项。 -
iterator():返回的是底层 List 的迭代器,因此也具备快照语义 —— 迭代期间即使集合被修改,也不会抛ConcurrentModificationException,且看不到新增元素。
为什么不用 HashMap 或其他结构?
因为 CopyOnWriteArrayList 的设计目标是读多写少、弱一致性场景下的线程安全列表,而 CopyOnWriteArraySet 需要继承其核心优势:无锁读、迭代安全、简单可靠。如果引入哈希表,就得处理哈希冲突、扩容、并发修改等复杂问题,违背了“写时复制”这种简单可预测的模型。牺牲 O(1) 查找换来了实现简洁与读性能极致优化。
使用注意点
由于每次 add() 都需 O(n) 遍历检查,CopyOnWriteArraySet 只适合元素数量小、写操作极少、读操作极频繁的场景(比如监听器注册表、配置白名单)。元素较多时,添加性能会明显下降;也不适合需要高频去重或复杂查询的业务。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











