当前位置: 首页 > news >正文

看图学源码之 CopyOnWriteArraySet源码分析

基本介绍

使用内部CopyOnWriteArrayList进行所有操作的Set

特点

  1. 它最适合以下应用程序:集合大小通常较小、只读操作的数量远远多于可变操作,并且您需要在遍历期间防止线程之间的干扰。
  2. 它是线程安全的。
  3. 突变操作( add 、 set 、 remove等)的成本很高,因为它们通常需要复制整个底层数组。
  4. 迭代器不支持变异remove操作。
  5. 通过迭代器进行遍历速度很快,并且不会遇到其他线程的干扰。迭代器依赖于构造迭代器时数组的不变快照。

源码分析

public class CopyOnWriteArraySet<E> extends AbstractSet<E>implements java.io.Serializable {private static final long serialVersionUID = 5457747651344034263L;private final CopyOnWriteArrayList<E> al;/*** Creates an empty set.*/public CopyOnWriteArraySet() {al = new CopyOnWriteArrayList<E>();}//创建一个包含指定集合的所有元素的集合public CopyOnWriteArraySet(Collection<? extends E> c) {if (c.getClass() == CopyOnWriteArraySet.class) {@SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =(CopyOnWriteArraySet<E>)c;al = new CopyOnWriteArrayList<E>(cc.al);}else {al = new CopyOnWriteArrayList<E>();al.addAllAbsent(c);}}//返回该集合中的元素数量public int size() {return al.size();}// 判断集合是不是为空public boolean isEmpty() {return al.isEmpty();}//返回一个包含该集合中所有元素的数组。如果此集合对其迭代器返回其元素的顺序做出任何保证,则此方法必须以相同的顺序返回元素。返回的数组将是“安全的”,因为该集合不维护对它的引用。 (换句话说,即使该集合由数组支持,此方法也必须分配一个新数组)。因此,调用者可以自由修改返回的数组。public Object[] toArray() {return al.toArray();}//返回一个包含该集合中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。如果该集合适合指定的数组,则将其返回其中。否则,将使用指定数组的运行时类型和该集合的大小分配一个新数组。//如果该集合适合指定的数组,并且有空闲空间(即该数组的元素多于该集合),则数组中紧随该集合末尾的元素将设置为null 。 (仅当调用者知道该集合不包含任何空元素时,这对于确定该集合的长度很有用。)//如果此集合对其迭代器返回其元素的顺序做出任何保证,则此方法必须以相同的顺序返回元素。public <T> T[] toArray(T[] a) {return al.toArray(a);}//仅保留此集中包含在指定集合中的元素。换句话说,从该集合中删除所有未包含在指定集合中的元素。如果指定的集合也是一个集合,则此操作会有效地修改该集合,使其值是两个集合的交集。public boolean retainAll(Collection<?> c) {return al.retainAll(c);}//按添加这些元素的顺序返回此集合中包含的元素的迭代器。//返回的迭代器提供了构造迭代器时集合状态的快照。遍历迭代器时不需要同步。迭代器不支持remove方法。public Iterator<E> iterator() {return al.iterator();}// 比较指定对象与该集合是否相等。如果指定的对象与此对象是同一对象,或者它也是Set ,并且指定集合上的迭代器返回的元素与此集合上的迭代器返回的元素相同,则返回true 。更正式地说,如果两个迭代器返回相同数量的元素,则认为它们返回相同的元素,并且对于迭代器在指定集合上返回的每个元素e1 ,迭代器在该集合上返回一个元素e2 ,使得(e1==null ? e2==null : e1.equals(e2)) public boolean equals(Object o) {if (o == this)return true;if (!(o instanceof Set))return false;Set<?> set = (Set<?>)(o);Iterator<?> it = set.iterator();// 使用仅适用于小集合的 O(n^2) 算法,CopyOnWriteArraySets 应该是这样的。// 使用底层阵列的单个快照Object[] elements = al.getArray();int len = elements.length;// Mark matched elements to avoid re-checkingboolean[] matched = new boolean[len];int k = 0;outer: while (it.hasNext()) {if (++k > len)return false;Object x = it.next();for (int i = 0; i < len; ++i) {if (!matched[i] && eq(x, elements[i])) {matched[i] = true;continue outer;}}return false;}return k == len;}public void forEach(Consumer<? super E> action) {al.forEach(action);}//按照添加这些元素的顺序返回此集合中元素的Spliterator public Spliterator<E> spliterator() {// 返回该集合中元素的Spliteratorreturn Spliterators.spliterator (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);}//试相等性,处理空值。private static boolean eq(Object o1, Object o2) {return (o1 == null) ? o2 == null : o1.equals(o2);}
}

contains
contains(Object o)

如果此集合包含指定元素,则返回true 。更正式地说,当且仅当该集合包含满足(onull ? enull : o.equals(e)) 的元素e时,才返回true 。

public boolean contains(Object o) {return al.contains(o);
}
containsAll(Collection<?> c)

如果此集合包含指定集合的所有元素,则返回true 。如果指定的集合也是一个集合,并且它是该集合的子集,则此方法返回true

public boolean containsAll(Collection<?> c) {return al.containsAll(c);
}

add
add(E e)

如果指定元素尚不存在,则将其添加到该集合中。更正式地说,如果集合不包含满足(e==null ? e2==null : e.equals(e2)) 的元素e2 ,则将指定元素e添加到此集合中。如果该集合已包含该元素,则调用将保持该集合不变并返回false

public boolean add(E e) {return al.addIfAbsent(e);
} 
addAll(Collection<? extends E> c)

将指定集合中的所有元素添加到该集合中(如果它们尚不存在)。如果指定的集合也是一个集合,则addAll操作会有效地修改此集合,使其值是两个集合的并集。如果在操作进行过程中修改了指定的集合,则该操作的行为是未定义的

public boolean addAll(Collection<? extends E> c) {return al.addAllAbsent(c) > 0;
}
remove
remove(Object o)

从此集合中删除指定元素(如果存在)。更正式地说,如果该集合包含这样的e ,则删除(o==null ? e==null : o.equals(e))的元素 e 。如果此集合包含该元素(或者等效地,如果此集合因调用而发生更改),则返回true 。 (一旦调用返回,该集合将不再包含该元素。)

public boolean remove(Object o) {return al.remove(o);
}
removeIf(Predicate<? super E> filter)

调用 CopyOnWriteArrayList 中的removeIf(filter)

public boolean removeIf(Predicate<? super E> filter) {return al.removeIf(filter);
}
removeAll(Collection<?> c)

从此集合中删除指定集合中包含的所有元素。如果指定的集合也是一个集合,则此操作有效地修改该集合,使其值为两个集合的非对称集合差。

public boolean removeAll(Collection<?> c) {return al.removeAll(c);
}
clear
clear()

删除该集合中的所有元素。该调用返回后该集合将为空。

public void clear() {al.clear();
}

总结

所有的方法都是调用 CopyOnWriteArrayList 对应的方法,所以其原理和实现可以观看上一章内容。

CopyOnWriteArraySet 和CopyOnWriteArrayList 的关系

CopyOnWriteArraySetSet 接口的实现类,它内部使用了 CopyOnWriteArrayList 来存储元素,CopyOnWriteArraySet的底层数据结构是一个 CopyOnWriteArrayList 对象。 每次进行写操作时都会创建一个新的数组副本,并在副本上进行修改,而不是直接在原始数组上进行修改。这样可以保证读操作的线程安全性,因为读操作可以在不加锁的情况下进行。

CopyOnWriteArrayList 也是一个线程安全的集合类,它实现了 List 接口。它的原理和 CopyOnWriteArraySet 类似,通过"写时复制"的机制来实现线程安全。每次进行写操作时,都会创建一个新的数组副本,并在副本上进行修改,从而保证读操作的线程安全性。

因此,可以说 CopyOnWriteArraySet 是在 CopyOnWriteArrayList 的基础上实现的,它在 CopyOnWriteArrayList 的基础上提供了 Set 接口的特性,即 元素不能重复。

去重的逻辑

去重的逻辑来源于:CopyOnWriteArraySet的add 方法会调用 CopyOnWriteArrayList中的addIfAbsent 方法,在 CopyOnWriteArrayList 中的addIfAbsent 会调用 indexOf(Object o, Object[] elements, int index, int fence) 来进行判断是不是存在,不存在再调用 addIfAbsent(e, snapshot)来进行添加元素。

相关文章:

看图学源码之 CopyOnWriteArraySet源码分析

基本介绍 使用内部CopyOnWriteArrayList进行所有操作的Set 特点 它最适合以下应用程序&#xff1a;集合大小通常较小、只读操作的数量远远多于可变操作&#xff0c;并且您需要在遍历期间防止线程之间的干扰。它是线程安全的。突变操作&#xff08; add 、 set 、 remove等&…...

almaLinux centos8 下载ffmpeg离线安装包、离线安装

脚本 # 添加RPMfusion仓库 sudo yum install https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm wget -ymkdir -p /root/ffmpeg cd /root/ffmpegwget http://rpmfind.net/linux/epel/7/x86_64/Packages/s/SDL2-2.0.14-2.el7.x86_64.rpmyum instal…...

CSS3 属性: transition过渡 与 transform动画

CSS3 提供了很多强大的功能&#xff0c;使开发人员可以创建更加吸引人的视觉效果&#xff0c;而不需要依赖于 JavaScript 或 Flash。其中&#xff0c;transition 和 transform 是两个常用的属性&#xff0c;它们分别用于创建平滑的过渡效果和元素的变形效果。下面我们将详细介绍…...

TCP通讯

第二十一章 网络通信 本章节主要讲解的是TCP和UDP两种通信方式它们都有着自己的优点和缺点 这两种通讯方式不通的地方就是TCP是一对一通信 UDP是一对多的通信方式 接下来会一一讲解 TCP通信 TCP通信方式呢 主要的通讯方式是一对一的通讯方式&#xff0c;也有着优点和缺点 …...

(NeRF学习)3D Gaussian Splatting Instant-NGP

学习参考&#xff1a; 3D Gaussian Splatting入门指南【五分钟学会渲染自己的NeRF模型&#xff0c;有手就行&#xff01;】 三维重建instant-ngp环境部署与colmap、ffmpeg的脚本参数使用 一、3D Gaussian Splatting &#xff08;一&#xff09;3D Gaussian Splatting环境配置…...

uni-app 微信小程序之好看的ui登录页面(三)

文章目录 1. 页面效果2. 页面样式代码 更多登录ui页面 uni-app 微信小程序之好看的ui登录页面&#xff08;一&#xff09; uni-app 微信小程序之好看的ui登录页面&#xff08;二&#xff09; uni-app 微信小程序之好看的ui登录页面&#xff08;三&#xff09; uni-app 微信小程…...

Android 默认打开应用的权限

有项目需要客户要安装第三方软件&#xff0c;但是要手动点击打开权限&#xff0c;就想不动手就打开。 //安装第三方软件&#xff0c;修改方式 frameworks\base\services\core\java\com\android\server\pm\PackageManagerService.java //找到如下源码&#xff1a; //有三种方…...

2023年广东工业大学腾讯杯新生程序设计竞赛

E.不知道叫什么名字 题意&#xff1a;找一段连续的区间&#xff0c;使得区间和为0且区间长度最大&#xff0c;输出区间长度。 思路&#xff1a;考虑前缀和&#xff0c;然后使用map去记录每个前缀和第一次出现的位置&#xff0c;然后对数组进行扫描即可。原理&#xff1a;若 s …...

FFmpeg开发笔记(六)如何访问Github下载FFmpeg源码

学习FFmpeg的时候&#xff0c;经常要到GitHub下载各种开源代码&#xff0c;比如FFmpeg的源码页面位于https://github.com/FFmpeg/FFmpeg。然而国内访问GitHub很不稳定&#xff0c;经常打不开该网站&#xff0c;比如在命令行执行下面的ping命令。 ping github.com 上面的ping结…...

SpringCloud | Dubbo 微服务实战——注册中心详解

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 |Eureka,Nacos,Consul,Zookeeper在Spring Cloud和Dubbo中实战 引言 在项目开发过程中&#xff0c;随着项目不断扩大&#xff0c;也就是业务的不断增多&#xff0c;我们将采用集群&#xf…...

PostGIS学习教程十一:投影数据

PostGIS学习教程十一&#xff1a;投影数据 地球不是平的&#xff0c;也没有简单的方法把它放在一张平面纸地图上&#xff08;或电脑屏幕上&#xff09;&#xff0c;所以人们想出了各种巧妙的解决方案&#xff08;投影&#xff09;。 每种投影方案都有优点和缺点&#xff0c;一…...

jQuery ajax读取本地json文件 三级联动下拉框

步骤 1&#xff1a;创建本地JSON文件 {"departments": [{"name": "会计学院","code": "052"},{"name": "金融学院","code": "053"},{"name": "财税学院",&qu…...

Kubernetes(K8s 1.27.x) 快速上手+实践,无废话纯享版(视频笔记)

视频源&#xff1a;1.03-k8s是什么&#xff1f;_哔哩哔哩_bilibili 1 基础知识 1.1 K8s 有用么&#xff1f; K8s有没有用 K8s要不要学&#xff1f; 参考资料: https://www.infoq.com/articles/devops-and-cloud-trends-2022/?itm_sourcearticles_about_InfoQ-trends-report…...

深度学习实战66-基于计算机视觉的自动驾驶技术,利用YOLOP模型实现车辆区域检测框、可行驶区域和车道线分割图

大家好,我是微学AI,今天给大家介绍一下深度学习实战66-基于计算机视觉的自动驾驶技术,利用YOLOP模型实现车辆区域检测框、可行驶区域和车道线分割图。本文我将介绍自动驾驶技术及其应用场景,并重点阐述了基于计算机视觉技术下的自动驾驶。自动驾驶技术是一种利用人工智能和…...

Stable Diffusion 系列教程 - 1 基础准备(针对新手)

使用SD有两种方式&#xff1a; 本地&#xff1a; 显卡要求&#xff1a;硬件环境推荐NVIDIA的具有8G显存的独立显卡&#xff0c;这个显存勉勉强强能摸到门槛。再往下的4G可能面临各种炸显存、炼丹失败、无法生成图片等各种问题。对于8G显存&#xff0c;1.0模型就不行&#xff0…...

听GPT 讲Rust源代码--src/tools(8)

File: rust/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs 在Rust源代码中&#xff0c;rust-analyzer是一个Rust编程语言的语言服务器。它提供了代码补全、代码重构和代码导航等功能来帮助开发者提高编码效率。 在rust-analyzer的代码目…...

Linux硬链接和软连接是什么?

在Linux操作系统中&#xff0c;文件管理是一个基本且重要的概念。其中&#xff0c;软链接&#xff08;Symbolic Link&#xff09;和硬链接&#xff08;Hard Link&#xff09;是文件系统中两种不同类型的链接方式&#xff0c;它们在文件管理和操作中扮演着重要的角色。软链接 软…...

LangChain 23 Agents中的Tools用于增强和扩展智能代理agent的功能

LangChain系列文章 LangChain 实现给动物取名字&#xff0c;LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄LangChain 4用向量数据库Faiss存储&#xff0c;读取YouTube的视频文本搜索I…...

VS2015编译GDAL3.2.0+opencl+C#

参考借鉴https://www.cnblogs.com/litou/p/15004877.html 参考借鉴https://www.cnblogs.com/xiaowangba/p/6313903.html 参考借鉴gdal、proj、geos、sqlite等在VS2015下编译和配置_vs2015编译sqlite3-CSDN博客 参考借鉴Windows下GDAL3.1.2编译 (VS2015)_gdal windows编译-CS…...

3、Linux_系统用户管理

1.Linux 用户管理 1.1概述 Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员申请一个账号&#xff0c;然后以这个账号的身份进入系统。root用户是系统默认创建的管理员账号。 1.2添加用户 语法 useradd […...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...