CopyOnWriteArraySet怎么用

简介
CopyOnWriteArraySet是一个线程安全的无序集合,它基于“写时复制”的思想实现。它继承自AbstractSet,可以将其理解成线程安全的HashSet。
CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程安全机制和CopyOnWriteArrayList一样,是通过volatile和互斥锁实现的。

应用场景
CopyOnWriteArraySet的应用场景主要是在并发编程中,特别是那些需要高并发的场景。它适用于数据量较小且读多写少的场景,例如,一个Web应用程序中的用户状态信息,这是一个读取操作远多于写入操作的典型场景。
它的线程安全机制避免了在迭代过程中其他线程对集合的修改操作引发的并发冲突,使得在迭代过程中可以安全地进行读取操作。然而,由于CopyOnWriteArraySet的写时复制机制,它可能存在一些性能开销,因此,如果需要频繁的写入操作,可能不适合使用CopyOnWriteArraySet。
总的来说,CopyOnWriteArraySet适合用在读多写少、对数据一致性要求不高、对线程安全性要求高的场景。

性能问题
CopyOnWriteArraySet的性能问题主要集中在以下几个方面:
- 写操作的开销 :由于CopyOnWriteArraySet采用的是写时复制的策略,每次写操作都需要复制一份底层数组,这会导致写操作的开销比较大。如果写操作比较频繁,可能会影响程序的性能。
- 内存占用 :由于每次写操作都需要复制一份底层数组,这会导致内存占用比较高。如果集合中的元素数量比较大,可能会导致内存溢出的问题。
- 迭代器的性能 :由于CopyOnWriteArraySet的迭代器是基于底层数组的快照实现的,如果在迭代过程中底层数组发生变化,迭代器不会反映这些变化。这可能会导致迭代器的性能不稳定,甚至引发并发问题。
针对以上问题,可以考虑以下优化策略:
- 使用其他线程安全集合类 :如果写操作比较频繁,可以考虑使用其他线程安全集合类,如ConcurrentHashMap或ConcurrentSkipListSet等。这些集合类采用了不同的同步策略,可以更好地支持并发访问。
- 控制集合的大小 :如果集合中的元素数量比较大,可以考虑控制集合的大小,避免内存溢出的问题。例如,可以设置集合的最大容量,当元素数量超过最大容量时进行清理或压缩操作。
- 减少迭代操作 :如果迭代操作比较频繁,可以考虑减少迭代操作的次数或使用其他方式来访问集合中的元素。例如,可以使用流(Stream) API 来处理集合中的元素,避免使用迭代器。
需要注意的是,在选择和优化线程安全集合类时需要根据具体的应用场景和需求进行权衡和选择。

源码解析
CopyOnWriteArraySet的源码实现相对比较简单,主要基于CopyOnWriteArrayList实现。以下是对CopyOnWriteArraySet源码的简单讲解:
public class CopyOnWriteArraySet<E> extends AbstractSet<E> {private final List<E> array;public CopyOnWriteArraySet() {this.array = new CopyOnWriteArrayList<>();}@Overridepublic boolean add(E e) {return array.add(e);}@Overridepublic boolean remove(Object o) {return array.remove(o);}@Overridepublic boolean contains(Object o) {return array.contains(o);}@Overridepublic int size() {return array.size();}@Overridepublic Iterator<E> iterator() {return new COWIterator<>(array.listIterator());}
}
在CopyOnWriteArraySet中,所有的操作都是通过调用CopyOnWriteArrayList的实现来完成的。CopyOnWriteArrayList的实现细节可以参考之前对CopyOnWriteArrayList的讲解。其中,COWIterator是一个简单的迭代器实现,用于包装ListIterator并确保线程安全。在迭代过程中,COWIterator会持有一个快照,不允许修改操作。

扩容机制
CopyOnWriteArraySet的扩容机制是基于CopyOnWriteArrayList实现的。当集合的元素数量超过当前数组的容量时,会创建一个新的数组,然后将原数组中的元素复制到新数组中。这个过程是线程安全的,因为整个复制过程是一个原子操作。
具体的扩容过程如下:
- 当集合的元素数量超过当前数组的容量时,会创建一个新的数组,大小是原数组的两倍。
- 然后将原数组中的元素复制到新数组中,每个元素复制的顺序是按照它们在原数组中的顺序。
- 复制完成后,将原数组清空,并将新数组赋值给集合的内部数组。
这种扩容机制的优点是可以在多线程环境下实现高效的并发访问,因为复制操作是一个原子操作,不会受到其他线程的干扰。同时,由于每次扩容时都会创建一个新的数组,因此可以避免因为元素插入导致的数组重新排列的开销。但是,由于每次扩容都需要创建一个新的数组并复制元素,所以如果集合中的元素数量非常大,扩容过程可能会比较耗时。
与CopyOnWriteArrayList的区别
CopyOnWriteArraySet和CopyOnWriteArrayList都是基于“写时复制”的思想实现的线程安全的数据结构,适用于读多写少的场景。它们的主要区别在于:
- 数据结构:CopyOnWriteArraySet是Set,而CopyOnWriteArrayList是List。因此,CopyOnWriteArraySet不允许存放重复值,而CopyOnWriteArrayList可以。
- 存储方式:CopyOnWriteArraySet内部持有一个CopyOnWriteArrayList引用,所有的操作都是由CopyOnWriteArrayList来实现的。它是无序的,不允许存放重复值。
- 迭代器行为:CopyOnWriteArraySet的迭代器使用了“快照”技术,存储了内部数组快照,不支持remove、set、add操作,但通过迭代器进行并发读取时效率很高。这是与CopyOnWriteArrayList的主要区别。
两者都是线程安全的数据结构,适用于读多写少的场景。主要区别在于数据结构、存储方式和迭代器行为。
代码示例
在多线程环境下,可以使用CopyOnWriteArraySet来保证线程安全。以下是一个简单的示例:
import java.util.concurrent.CopyOnWriteArraySet;public class Example {private static CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();public static void main(String[] args) {new Thread(() -> {for (int i = 0; i < 5000; i++) {set.add("a" + System.currentTimeMillis());}}).start();new Thread(() -> {for (int i = 0; i < 5000; i++) {set.add("b" + System.currentTimeMillis());}}).start();}
}
在这个示例中,我们创建了一个CopyOnWriteArraySet,并启动了两个线程,每个线程都向集合中添加元素。由于CopyOnWriteArraySet是线程安全的,因此在迭代过程中,其他线程对集合的修改操作不会引发并发冲突。

拓展
- 线程安全集合类
除了CopyOnWriteArraySet和CopyOnWriteArrayList,Java中还有其他一些线程安全的集合类,包括:
- ConcurrentHashMap:线程安全的Map实现,使用分段锁技术实现并发访问。
- ConcurrentSkipListMap:基于跳表(Skip List)实现的线程安全Map,具有较高的并发性能。
- ConcurrentLinkedQueue:基于链接节点的线程安全队列,支持高效的并发访问。
- ConcurrentSkipListSet:基于跳表(Skip List)实现的线程安全Set,具有较高的并发性能。
这些线程安全集合类的使用方法和普通的集合类类似,但它们能够在多线程环境下提供更好的并发性能和数据安全性。
-
CopyOnWriteArrayList讲解
快点我呀✋🏻 -
更多集合
ConcurrentLinkedDeque详解-Deque接口链表实现方案
ArrayDeque详解-Deque接口数组实现方案
LinkedList详解-Deque接口链表实现方案
Java中Deque接口方法解析
相关文章:
CopyOnWriteArraySet怎么用
简介 CopyOnWriteArraySet是一个线程安全的无序集合,它基于“写时复制”的思想实现。它继承自AbstractSet,可以将其理解成线程安全的HashSet。 CopyOnWriteArraySet在读取操作比较频繁、写入操作相对较少的情况下可以提高程序的性能和可靠性。它的线程…...
uniapp得app云打包问题
获取appid,具体可以查看详情 也可以配置图标,获取直接生成即可 发行 打包配置 自有证书测试使用时候不需要使用 编译打包 最后找到安装包apk安装到手机 打包前,图片命名使用要非中文,否则无法打包成功会报错...
Linux bin包生成
需求背景: 在实际项目时我们很少把源码用个tar给到客户,这样显得很不专业,且有的时候我们提供补丁,那么这个时候我们提供一个补丁的bin包可以直接安装运行就显得很高大上了。 物料准备 准备一台liunx,虚拟机亦可&am…...
Java多人聊天
服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…...
自动驾驶:传感器初始标定
手眼标定 机器人手眼标定AxxB(eye to hand和eye in hand)及平面九点法标定 Ax xB问题求解,旋转和平移分步求解法 手眼标定AXXB求解方法(文献总结) 基于靶的方法 相机标定 (1) ApriTag (2) 棋盘格:cv::f…...
如何将 MySQL 数据库转换为 SQL Server
本文解释了为什么组织希望将其 MySQL 数据库转换为 Microsoft SQL 数据库。本文接着详细介绍了尝试转换之前需要记住的事项以及所涉及的方法。专业的数据库转换器工具将帮助您快速将 MySQL 数据库记录转换为 MS SQL Server。 在继续之前,我们先讨论一下 MySQL 到 M…...
【开源】基于Vue+SpringBoot的河南软件客服系统
文末获取源码,项目编号: S 067 。 \color{red}{文末获取源码,项目编号:S067。} 文末获取源码,项目编号:S067。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、…...
《算法面试宝典》--深度学习常见问题汇总
第三章 深度学习基础 3.1 基本概念 3.1.1 神经网络组成? 神经网络类型众多,其中最为重要的是多层感知机。为了详细地描述神经网络,我们先从最简单的神经网络说起。 感知机 多层感知机中的特征神经元模型称为感知机,由Frank Rosenblatt于1957年发明。 其中 x 1 x_1 x...
【计算机网络实验】实验三 IP网络规划与路由设计(头歌)
目录 一、知识点 二、实验任务 三、头歌测试 一、知识点 IP子网掩码的两种表示方法 32位IP子网掩码,特点是从高位开始连续都是1,后面是连续的0,它有以下两种表示方法: 传统表示法,如:255.255.255.0IP前…...
CodeBlocks添加头文件,解决fatal error: ui.h No such file or directory
问题描述 在使用codeblocks工具进行LVGL仿真过程中报错,找不到头文件 原因分析: 没有将头文件加入编辑器搜索的目录中,编译时找不到头文件。 解决方案: 将要包含的头文件的目录加进去就可以了...
鸿蒙开发:UIAbility组件与UI的数据同步-使用EventHub进行数据通信【鸿蒙专栏-21】
文章目录 ArkTS应用模型中UIAbility组件与UI的数据同步使用EventHub进行数据通信使用globalThis进行数据同步1. UIAbility和Page之间使用globalThis2. UIAbility和UIAbility之间使用globalThis3. 使用globalThis的注意事项4. 使用globalThis的注意事项同名对象覆盖导致问题的场…...
云架构的思考3--云上开发
目录 1 DevOps--简单灵活性高2 服务化(微服务)--弹性(可扩展)、按需自主服务3 无状态(Serverless)--弹性(可扩展)4 日志--安全5 配置中心--安全6 设计模式6.1 使用“适配器模式”调用…...
vue3日常知识点学习归纳
1,父子组件传递: 父组件传递参数 <template><div><!-- 子组件 参数:num 、nums --><child :num"nums.num" :doubleNum"nums.doubleNum" increase"handleIncrease"></child>&l…...
策略模式终极解决方案之策略机
我们在开发时经常会遇到一堆的if else …, 或者switch, 比如我们常见的全局异常处理等, 像类似这种很多if else 或者多场景模式下, 策略模式是非常受欢迎的一种设计模式, 然而, 一个好的策略模式却不是那么容易写出来. 我在工作中也因为写烦了switch,if else 觉得很不优雅, 因…...
linux 常用指令目录大纲
Linux下的Signal信号处理及详解,test ok-CSDN博客 Linux下怎样判断一个binary是否可以debug//test ok_感知算法工程师的博客-CSDN博客 linux file命令的用法//test ok-CSDN博客 linux下生成core dump方法与gdb解析core dump文件//test ok-CSDN博客 linux readel…...
webpack该如何打包
1.我们先创建一个空的大文件夹 2.打开该文件夹的终端 输入npm init -y 2.1.打开该文件夹的终端 2.2在该终端运行 npm init -y 3.安装webpack 3.1打开webpack网址 点击“中文文档” 3.2点击“指南”在点击“起步” 3.3复制基本安装图片画线的代码 4.在一开始的文件夹下在创建一…...
【STM32】TIM定时器输入捕获
1 输入捕获 1.1 输入捕获简介 IC(Input Capture)输入捕获 输入捕获模式下,当通道输入引脚出现指定电平跳变时(上升沿/下降沿),当前CNT的值将被锁存到CCR中(把CNT的值读出来,写入到…...
webrtc 设置不获取鼠标 启用回声消除
数 getDisplayMedia()(属于 navigator.mediaDevices 的一部分)与 getUserMedia() 类似,用于打开显示内容(或部分内容,如窗口)。返回的 MediaStream 与使用 getUserMedia() 时相同。 显示鼠标与否 getDisplayMedia() 的约束条件与常规视频或音频输入资源的限制不同。 {…...
JVM虚拟机:如何查看JVM初始和最终的参数?
本文重点 在前面的课程中,我们学习了如何查看当前程序所处于的xx参数,本文再介绍一种如何参看JVM的xx参数? 查看JVM的所有初始化参数 方式一:java -XX:PrintFlagsInitial 方式二:java -XX:PrintFlagsInitial -versio…...
JVM Optimization Learning(五)
目录 一、JVM Optimization 1、G1 1、G1内存模型 2、基础概念 3、G1特点: 4、CMS日志分析 5、G1日志分析 2、GC参数 2.1、GC常用参数 2.2、Parallel常用参数 2.3、CMS常用参数 2.4、G1常用参数 一、JVM Optimization 1、G1 G1官网说明:Gar…...
DeepSeek API实战:如何用Python脚本绕过Postman直接调用(附完整代码)
DeepSeek API高效调用指南:Python脚本开发实战 在当今快节奏的开发环境中,效率是衡量开发者生产力的关键指标。传统API测试工具如Postman虽然功能强大,但在自动化流程和持续集成场景中往往显得笨重。本文将带你探索一种更轻量、更灵活的解决方…...
【20年JVM老兵亲测】Java 25密封类+模式匹配+记录类三重协同时,API设计效率提升47%!
第一章:Java 25密封类扩展特性的演进脉络与设计哲学Java 密封类(Sealed Classes)自 Java 15 作为预览特性引入,历经 Java 16、17 的持续迭代,最终在 Java 17 成为正式特性。而 Java 25 进一步拓展其能力边界࿰…...
Windows屏保设置失效?解锁注册表权限的终极指南
1. 为什么你的Windows屏保设置突然失效了? 最近有没有遇到过这种情况:明明想设置个屏保保护隐私,却发现所有选项都变成灰色不可点击?这个问题我帮不少朋友解决过,其实90%的情况都是注册表权限在作怪。Windows系统有个特…...
原神抽卡记录导出工具:一键备份分析你的抽卡历史数据
原神抽卡记录导出工具:一键备份分析你的抽卡历史数据 【免费下载链接】genshin-wish-export biuuu/genshin-wish-export - 一个使用Electron制作的原神祈愿记录导出工具,它可以通过读取游戏日志或代理模式获取访问游戏祈愿记录API所需的authKey。 项目…...
Simulink模型到AUTOSAR RTE的‘最后一公里’:手把手教你处理ARXML接口冲突并自动配置ISOLAR
Simulink模型到AUTOSAR RTE的‘最后一公里’:手把手教你处理ARXML接口冲突并自动配置ISOLAR 在汽车电子软件开发中,Simulink与AUTOSAR工具链的集成已经成为行业标配。但当你满怀期待地将Simulink模型导出为ARXML文件,准备导入ISOLAR进行后续开…...
Parallax三线LCD Arduino驱动库详解
1. 项目概述 Parallax LCD 是一个专为驱动 Parallax 公司三线制串行 LCD 模块设计的轻量级 Arduino 库。该库不依赖标准 HD44780 并行接口协议,而是针对 Parallax 自研的 3 线串行通信协议(TX、GND、VDD)进行底层适配,显著降低 GP…...
R200系列超高频读写器:从指令集到实战的物联网资产管理开发指南
1. R200系列读写器:物联网资产管理的利器 第一次接触R200系列读写器时,我就被它的多标签识读能力惊艳到了。这款超高频(UHF)读写器不仅支持840MHz~960MHz频段,还能在30米范围内同时读取上百张RFID标签,这简…...
STM32单片机电机PID控制技术详解
STM32单片机实现电机PID控制技术解析1. 项目概述PID控制算法作为经典控制理论的核心算法,在工业控制领域已有近百年的应用历史。在电机控制场景中,PID算法通过调节PWM占空比实现对电机转速或位置的精确控制。本项目基于STM32单片机平台,实现了…...
Wireshark网络协议分析技术与实践指南
1. 网络协议分析技术概述1.1 Wireshark工具简介Wireshark(前称Ethereal)是目前最主流的开源网络协议分析工具,采用WinPCAP接口直接与网卡进行数据报文交换。该工具支持超过2000种网络协议的解析,能够实时捕获和分析网络数据包。1.…...
FireRed-OCR StudioGPU适配方案:多卡并行解析长文档的配置详解
FireRed-OCR StudioGPU适配方案:多卡并行解析长文档的配置详解 1. 工业级文档解析工具概述 FireRed-OCR Studio是一款基于Qwen3-VL模型开发的下一代文档解析工具,专为处理复杂文档场景设计。它不仅能够精准识别文字内容,更能完整还原文档中…...
