news 2026/1/29 10:23:14

揭秘CopyOnWriteArraySet:读多写少的并发集合利器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
揭秘CopyOnWriteArraySet:读多写少的并发集合利器

文章目录

    • 什么是CopyOnWriteArraySet?
    • 核心原理深度剖析
      • 底层数据结构
      • 写时复制机制详解
      • 迭代器的弱一致性
    • 与其它容器的性能对比
    • 实际应用场景
      • 1. 配置信息管理
      • 2. 在线用户状态收集器
      • 3. 事件监听器管理
    • 实战案例:高并发在线用户监测
    • 局限性及注意事项
    • 总结
    • 参考文章

大家好,我是你们的技术老友科威舟,今天给大家分享一下Java JUC包中的CopyOnWriteArraySet原理。

如何在高并发读取场景中既保证线程安全又提升性能?CopyOnWriteArraySet或许正是你要找的解决方案。

在多线程编程的世界里,线程安全始终是我们需要直面的挑战。当涉及到共享集合时,这种挑战尤为突出。今天,我们要深入剖析的是一位在并发编程中不可或缺的"特长生"——CopyOnWriteArraySet。

什么是CopyOnWriteArraySet?

简单来说,CopyOnWriteArraySet是Java并发包(java.util.concurrent)中提供的一个线程安全的Set实现。它与众不同之处在于采用了"写时复制"(Copy-On-Write)策略,这意味着每次修改操作(如添加、删除元素)都会创建底层数组的一个新副本,而读操作则直接在原数组上进行。

想象一下图书馆的管理方式:当有人只想查阅书籍(读操作)时,可以直接进入书库浏览;但当需要增加或下架书籍(写操作)时,管理员会先创建一个完整的书库副本,在副本上进行修改,最后再用修改后的副本替换原始书库。这样,查阅者永远不会被阻塞,但修改操作的成本较高。

核心原理深度剖析

底层数据结构

CopyOnWriteArraySet的巧妙之处在于其内部实现:它完全依赖CopyOnWriteArrayList作为其存储结构。

publicclassCopyOnWriteArraySet<E>extendsAbstractSet<E>implementsjava.io.Serializable{// 内部使用CopyOnWriteArrayList来存储元素privatefinalCopyOnWriteArrayList<E>al;publicCopyOnWriteArraySet(){al=newCopyOnWriteArrayList<E>();}}

这里就产生了一个有趣的问题:CopyOnWriteArrayList本身允许元素重复,而Set要求元素唯一。CopyOnWriteArraySet如何解决这一矛盾?

答案是它通过调用CopyOnWriteArrayList的addIfAbsent方法来确保元素的唯一性。

写时复制机制详解

添加元素的流程体现了写时复制的精髓:

publicbooleanadd(Ee){// 调用addIfAbsent方法,确保元素不存在时才添加returnal.addIfAbsent(e);}

addIfAbsent方法内部会先检查元素是否已存在,只有在元素不存在时才会执行添加操作。添加过程需要获取可重入锁,然后创建原数组的副本,在新副本上添加元素,最后将副本设置为新的当前数组。

这一过程保证了写操作的原子性和线程安全,但代价是每次写操作都需要复制整个数组,因此写操作的性能与数组大小成正比。

迭代器的弱一致性

CopyOnWriteArraySet的迭代器具有弱一致性特征,这意味着迭代器创建时会获取当前数组的快照,在迭代过程中不会反映其他线程对集合的修改。这避免了ConcurrentModificationException异常,但代价是可能遍历到过期的数据。

publicIterator<E>iterator(){// 返回一个基于当前数组快照的迭代器returnal.iterator();}

与其它容器的性能对比

为了更直观地理解CopyOnWriteArraySet的特性,我们通过一个表格比较它与其它常见容器的区别:

特性HashSetConcurrentHashMap.KeySetViewCopyOnWriteArraySet
读性能O(1)O(1)O(n)但无锁
写性能O(1)O(1)带锁竞争O(n)复制开销
内存消耗最低中等较高(写时复制)
迭代器一致性弱一致性弱一致性强一致性(快照)
适用场景单线程环境高频读写低频写+高频读

从对比中可以看出,CopyOnWriteArraySet在读多写少的场景中具有明显优势,特别是在需要频繁遍历且写操作较少的并发环境中。

实际应用场景

1. 配置信息管理

在大型系统中,配置信息通常只在启动时加载,之后会被多个线程频繁读取,但极少修改。使用CopyOnWriteArraySet存储配置项,可以保证在高并发读取时的性能。

publicclassConfigurationManager{privatefinalCopyOnWriteArraySet<ConfigListener>listeners=newCopyOnWriteArraySet<>();// 添加配置监听器(写操作少)publicvoidaddListener(ConfigListenerlistener){listeners.add(listener);}// 通知所有监听器(读操作多)publicvoidfireConfigChanged(ConfigEventevent){for(ConfigListenerlistener:listeners){listener.onConfigChanged(event);}}}

2. 在线用户状态收集器

电商平台需要实时跟踪在线用户状态,这类场景中读取频率远高于写入频率

publicclassOnlineUserManager{privatefinalCopyOnWriteArraySet<Long>onlineUsers=newCopyOnWriteArraySet<>();// 用户登录(写操作)publicbooleanuserLogin(LonguserId){booleanadded=onlineUsers.add(userId);if(added){log.info("用户{}登录成功,当前在线人数:{}",userId,onlineUsers.size());}returnadded;}// 获取在线用户列表(读操作)publicSet<Long>getOnlineUsers(){returnCollections.unmodifiableSet(onlineUsers);}}

3. 事件监听器管理

GUI框架或事件驱动系统中,监听器通常在初始化时注册,之后主要进行遍历操作以通知事件,这正是CopyOnWriteArraySet的用武之地。

实战案例:高并发在线用户监测

以下是一个基于Spring Boot的在线用户监测系统完整示例,展示了CopyOnWriteArraySet在生产环境中的应用:

@ComponentpublicclassOnlineUserManager{privatefinalCopyOnWriteArraySet<Long>onlineUsers=newCopyOnWriteArraySet<>();privatefinalConcurrentMap<Long,Long>lastHeartbeat=newConcurrentHashMap<>();privatestaticfinallongHEARTBEAT_TIMEOUT=300_000;// 5分钟// 用户登录publicbooleanuserLogin(LonguserId){booleanresult=onlineUsers.add(userId);if(result){lastHeartbeat.put(userId,System.currentTimeMillis());}returnresult;}// 心跳保活publicvoidrefreshHeartbeat(LonguserId){if(onlineUsers.contains(userId)){lastHeartbeat.put(userId,System.currentTimeMillis());}}// 定时清理超时用户publicvoidcleanExpiredUsers(){longnow=System.currentTimeMillis();for(LonguserId:onlineUsers){LonglastTime=lastHeartbeat.get(userId);if(lastTime!=null&&now-lastTime>HEARTBEAT_TIMEOUT){onlineUsers.remove(userId);lastHeartbeat.remove(userId);}}}}

这个实现能够支持5000+ QPS的并发读取压力,同时保证用户登录/登出操作的原子性。

局限性及注意事项

尽管CopyOnWriteArraySet在特定场景下表现优秀,但它并非万能钥匙,存在以下局限性:

  1. 内存开销大:写操作需要复制整个数组,内存占用较高
  2. 实时性弱:读操作可能无法立即看到其他线程的最新修改
  3. 写性能随数据量增长而下降:不适合存储大量数据且写操作频繁的场景

总结

CopyOnWriteArraySet是Java并发包中一颗璀璨的明珠,它在读多写少的并发场景中表现卓越。通过写时复制机制,它实现了读操作的无锁并发,特别适合配置管理、事件监听、会话管理等场景。

但是,选择数据结构时一定要根据实际应用场景权衡利弊。如果你的应用写操作频繁数据量巨大,那么ConcurrentHashMap.KeySetView可能是更好的选择。

技术选型的艺术不在于选择最先进的技术,而在于选择最合适的技术。CopyOnWriteArraySet的存在再次证明了这一原则:在正确的场景下,即使看似"低效"的复制整个数组的策略,也能成为解决高并发问题的利器。

参考文章

  1. [Java CopyOnWriteArraySet源码深度解析 - CSDN]
  2. [深度剖析 Java CopyOnWriteArraySet:源码级使用原理揭秘 - 51CTO]
  3. [揭秘 Java CopyOnWriteArraySet:深入源码剖析使用原理 - CSDN]
  4. [CopyOnWriteArraySet - CSDN]
  5. [JUC集合类 CopyOnWriteArraySet源码解析 JDK8 - CSDN]
  6. [基于CopyOnWriteArraySet的高并发在线用户状态收集器架构设计 - CSDN]
  7. [如何在Java中使用CopyOnWriteArraySet - PHP中文网]
  • 本文主要观点基于以上参考资料,结合实际开发经验整理而成。转载请注明出处。*

更多技术干货欢迎关注微信公众号科威舟的AI笔记~

【转载须知】:转载请注明原文出处及作者信息

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/27 23:13:06

CSDN年度技术趋势预测

CSDN技术趋势预测概览CSDN作为国内知名的开发者社区&#xff0c;每年会基于行业动态、用户行为及专家分析发布技术趋势预测。以下是综合多方信息整理的2023年重点关注领域&#xff1a;人工智能与机器学习生成式AI&#xff08;如ChatGPT、Stable Diffusion&#xff09;持续爆发&…

作者头像 李华
网站建设 2026/1/27 8:20:24

AI应用架构师注意!企业AI伦理审查机制背后的关键逻辑

企业AI伦理审查机制背后的关键逻辑&#xff1a;从“合规枷锁”到“可持续发展引擎” 一、引入与连接&#xff1a;当AI“犯错”时&#xff0c;企业该如何负责&#xff1f; 1. 一个真实的“伦理危机”故事 2018年&#xff0c;亚马逊悄悄停用了其开发的AI招聘工具。这款工具原本旨…

作者头像 李华
网站建设 2026/1/27 7:54:03

async 和 await 详细解析

Python async 和 await 详细解析 async 和 await 是 Python 3.5 及以上版本引入的异步编程核心语法&#xff0c;用于实现「非阻塞式」代码执行&#xff0c;解决传统同步编程中高IO等待&#xff08;如网络请求、数据库操作、文件读写&#xff09;导致的资源浪费问题&#xff0c;…

作者头像 李华
网站建设 2026/1/28 8:56:38

SEER癌症数据库(The Surveillance, Epidemiology, and End Results)

SEER数据库&#xff08;The Surveillance, Epidemiology, and End Results&#xff09; 发布时间&#xff1a;2023-12-22浏览量&#xff1a;1901 1. 数据集名称: SEER&#xff08;The Surveillance,Epidemiology,and End Results&#xff09; 2. 数据集基本情况: •项目背…

作者头像 李华
网站建设 2026/1/27 21:31:05

Linux 字符设备驱动中 “主次设备号的静态 / 动态分配” 实验

这个实验是Linux 字符设备驱动中 “主次设备号的静态 / 动态分配” 实验&#xff0c;核心是验证 “手动指定设备号” 和 “内核自动分配设备号” 两种方式&#xff0c;步骤如下&#xff1a;一、环境准备和之前的信号量实验一致&#xff1a;安装对应架构的交叉编译工具链&#x…

作者头像 李华
网站建设 2026/1/28 20:20:39

Java毕设项目推荐-基于Spring Boot与MySQL的二手车销售管理系统的设计与实现基于Java和Spring Boot的二手车交易系统设计与实现【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华