发布于2026-07-09 阅读(0)
扫一扫,手机访问
我们先说结论:CopyOnWriteArraySet 这个类,其实就一句话——它只适合读多写少、对实时性要求不高的并发场景。比如监听器列表、配置白名单、状态枚举缓存,这些集合通常初始化后极少修改,但会被大量线程频繁遍历。反过来,如果你的集合每秒要新增几十次,或者元素数量上千,那它反而会拖慢性能,因为每次写操作(add、remove)都会复制整个底层数组,写开销大、内存占用高。

说白了,只适合读多写少、对实时性要求不高的场景。底层用 CopyOnWriteArrayList 实现,每次写操作都会复制整个数组,所以写入开销大、内存占用高。如果你的集合每秒新增几十次,或者元素有上千个,CopyOnWriteArraySet 反而会拖慢整体性能。
典型适用场景:监听器列表、配置白名单、状态枚举缓存——这些通常初始化后极少修改,但被大量线程频繁遍历。
它依赖元素的 equals() 和 hashCode() 判断是否已存在,逻辑和 HashSet 一致,不是靠引用比较。这意味着如果你没重写这两个方法,自定义对象即使内容相同也会被当作不同元素加入。
equals() 和 hashCode()null 元素,调用 add(null) 会直接抛 NullPointerExceptioniterator() 都是安全的,不会抛 ConcurrentModificationException表面看都是线程安全的 Set,但行为差异很大:Collections.synchronizedSet 是阻塞式加锁,所有读写串行;而 CopyOnWriteArraySet 的读完全无锁,写则复制+替换引用。这意味着:
remove 的元素仍可能出现在这次遍历中size() 返回的是快照大小,调用后立刻有其他线程 add,结果也不反映在该次调用里addAll 批量去重:它只是循环调用 add,不会预先合并重复项,性能比预期差如果写操作频繁,或者需要强一致性视图(比如“添加后立刻能被下一次遍历看到”),就别硬扛 CopyOnWriteArraySet。可以考虑:
ConcurrentHashMap.newKeySet()(Ja va 8+):基于分段锁,读写都高效,支持 null 以外的任意非空键,语义最接近传统 SetConcurrentHashMap 模拟,key 即元素,value 固定为 Boolean.TRUEExecutorService 串行提交),其余线程只读——这时普通 HashSet + volatile 引用也能 work真正麻烦的从来不是选哪个类,而是没想清楚“我到底要的是最终一致性,还是强一致性”。CopyOnWriteArraySet 给的是前者,而且代价明确——每次写都在悄悄复制整块内存。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8