详解CopyOnWriteArraySet在并发读多写少场景应用

老浩吖_5568

老浩吖_5568

2026-04-02

570人浏览

原创

copyonwritearrayset适合读多写少场景,因其读操作无锁高性能,写操作通过复制数组实现线程安全,但开销大、内存高、不支持null且弱一致性。

详解copyonwritearrayset在并发读多写少场景应用

CopyOnWriteArraySet 是 Java 并发包(java.util.concurrent)中一个线程安全的 Set 实现,底层基于 CopyOnWriteArrayList 构建。它特别适合“读多写少”的并发场景——即多个线程频繁读取、极少修改集合内容的使用模式。

为什么 CopyOnWriteArraySet 适合读多写少?

它的核心机制是“写时复制”(Copy-On-Write):每次添加、删除或更新元素时,并不直接修改原数组,而是先复制一份新数组,在新数组上完成操作,再用原子方式替换原引用。这意味着:

  • 读操作(如 contains()、iterator()、size())完全无锁,也不阻塞其他读线程,性能极高;
  • 写操作(如 add()、remove())开销较大——涉及数组复制、对象创建和 volatile 引用更新,且会阻塞其他写操作;
  • 迭代器是快照式的,不会抛出 ConcurrentModificationException,但看不到写操作的最新结果(弱一致性)。

典型适用场景举例

以下情况可优先考虑 CopyOnWriteArraySet:

  • 监听器/观察者列表:例如事件总线中注册的监听器集合,通常初始化后很少增删,但每次事件触发都要遍历通知;
  • 配置白名单或黑名单:如 IP 白名单集合,加载后长期只读,仅运维偶尔动态更新;
  • 缓存中的活跃会话 ID 集合:大量查询是否存在某会话,新增/下线频率远低于查询频率。

使用时需注意的关键细节

它不是万能替代品,误用反而降低性能或引发逻辑问题:

  • 不支持 null 元素:调用 add(null) 会直接抛出 NullPointerException;
  • 不保证实时可见性:写操作完成后,正在执行的迭代器仍遍历旧快照,新线程读取才可见;
  • 内存占用较高:每次写操作都复制整个底层数组,集合大、写频繁时易引发 GC 压力;
  • 不支持批量写入优化:如 addAll() 仍是逐个 add,无法合并为一次复制。

对比其他线程安全 Set 的选择建议

若场景不符合“读远多于写”,应考虑更合适的方案:

  • 读写均衡或写较多 → 用 Collections.synchronizedSet(new HashSet()) 或 ConcurrentHashMap.newKeySet()(JDK 8+);
  • 需要强一致性 + 高并发写 → 优先选 ConcurrentSkipListSet(基于跳表,支持排序与并发修改);
  • 仅需简单存在性判断且允许一定延迟 → 可用 ConcurrentHashMap 模拟(map.put(key, Boolean.TRUE)),空间和性能更优。
PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

2023.11.13

2090

6

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.30

143

8

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

2023.09.22

529

3

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

2024.03.01

1658

6

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

2025.10.23

694

12

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

3638

6

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

2025.09.05

450

5

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

2025.11.16

323

7

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

2025.11.17

493

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习