看图学源码之 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)来进行添加元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/206006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

主动而非被动:确保网络安全运营弹性的途径

金融部门处理威胁的经验对网络安全领域的任何人都有启发——没有什么可以替代提前摆脱潜在的风险和问题。 从狂野西部的银行劫匪到勒索软件即服务 (RaaS)&#xff0c;全球金融生态系统面临的威胁多年来发生了巨大变化。技术进步带动了金融业的快速发展&#xff0c;从现金交易到…

基于轻量级MnasNet模型开发构建40种常见中草药图像识别系统

文本是前文的后续&#xff1a; 《python基于轻量级GhostNet模型开发构建23种常见中草药图像识别系统》 前文主要是在小批量小种类数据集上尝试开发构建基于轻量级CNN模型的中草药图像识别系统&#xff0c;本文的初衷是想要构建一个大类别大数据集的基础&#xff0c;但是无奈发…

附录1、vuepress中的Markdown语法

# 一、标题 # 说明&#xff1a; #后面跟的内容就是标题&#xff0c;一个#就是一级标题&#xff0c;有几个#就是几级标题&#xff0c;例如2级标题就有两个##&#xff0c;markdown的2级和3级标题会默认自动作为子目录&#xff0c; 注意&#xff1a;#后面必须有个空格&#xff0…

【天线了解】2.WTW天线了解与使用

注意网段&#xff1a;&#xff08;计算机与设备同一网段才可以通信&#xff09; 1.LS28接收机使用的网段是192.168.16.X&#xff0c;所以电脑应该同样设置 2.WTW天线使用网段192.168.98.X 0.WTW使用原理 1.计算机控制LS28&#xff08;接收机&#xff09;&#xff0c;WTW天线。 …

全志H6-ARMLinux第1天:全志概述、刷机登陆、官方外设库、蜂鸣器、超声波测距

1. 全志H616课程概述&#xff08;456.01&#xff09; 1.1 为什么学 学习目标依然是Linux系统&#xff0c;平台是ARM架构 蜂巢快递柜&#xff0c;配送机器人&#xff0c;这些应用场景用 C51、STM32 单片机无法实现第三方介入库的局限性&#xff0c;比如刷脸支付和公交车收费设…

《微信小程序开发从入门到实战》学习四十四

4.3 云开发文件存储 4.3.4 删除文件 在小程序端和云函数端&#xff0c;都可以调用API删除云空间中的文件&#xff0c;这两个API的参数和回调函数参数都是一样。每次调用API最多删除50个文件。使用方法如下代码所示&#xff1a; // 回调风格的API wx.cloud.deleteFile({ file…

python的extend函数详解

文章目录 语法功能示例例1&#xff1a;添加列表例2&#xff1a;添加元组例3&#xff1a;添加集合例4&#xff1a;添加字典&#xff08;只添加键&#xff09;例5&#xff1a;添加字符串例6&#xff1a;混合类型扩展例7&#xff1a;扩展空列表或不可迭代对象 注意事项&#xff1a…

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境

PHP使用mkcert本地开发生成HTTPS证书 PhpEnv集成环境 前言一、介绍 mkcert二、安装/使用 mkcert1. 安装2. 使用 总结 前言 本地开发时有些功能只有在 https 证书的情况下才能使用, 例如一些 Web API 一、介绍 mkcert Github地址 mkcert 是一个制作本地可信开发证书的简单工具。…

SmartChart:一站式数据可视化解决方案

在当今的数据驱动的世界中&#xff0c;数据可视化已经成为了一个重要的工具&#xff0c;它可以帮助我们理解复杂的数据集&#xff0c;并从中提取有价值的信息。SmartChart就是这样一个强大的数据可视化工具&#xff0c;它提供了一站式的数据可视化解决方案&#xff0c;无论你是…

Docker实战笔记 二 Springboot Idea 插件打包

1.上传springboot的jar rootcenots-7.5:/home/code#rz -----app.jar 2.编辑Dockerfile rootcenots-7.5:/home/code#vi Dockerfile内容 FROM openjdk:8 # 作者 MAINTAINER nnd # 声明要使用的端口 EXPOSE 8080 # VOLUME 指定了临时文件目录为/tmp。# 将本地包添加到容器中并…

力扣题:字符的统计-12.7

力扣题-12.7 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;467. 环绕字符串中唯一的子字符串 解题思想&#xff1a;记录下以字母s[i]结尾的最大的字串个数&#xff0c;然后统计a-z每个字母结尾的最大字串的个数进行i相加 class Solution(object…

DDD架构思想专栏一《初识领域驱动设计DDD落地》

引言 最近准备给自己之前写的项目做重构&#xff0c;这是一个单体架构的小项目&#xff0c;后端采用的是最常见的三层架构。因为项目比较简单&#xff0c;其实采用三层架构就完全够了。但是呢&#xff0c;小编最近在做DDD架构的项目&#xff0c;于是就先拿之前写的一个老项目试…

1319:【例6.1】排队接水

【题目描述】 有n 个人在一个水龙头前排队接水&#xff0c;假如每个人接水的时间为Ti &#xff0c;请编程找出这n 个人排队的一种顺序&#xff0c;使得n 个人的平均等待时间最小。 【输入】 共两行&#xff0c;第一行为n(1≤n≤1000) &#xff1b;第二行分别表示第1 个人到第n…

从传统到胜利:广汽集团汽车产业创新之旅

置身于汽车行业百年未有之大变局&#xff0c;作为传统车企中的排头兵&#xff0c;广汽创新可圈可点&#xff0c;广汽近年来取得了骄人业绩&#xff0c;不论是整体产销规模&#xff0c;还是新能源汽车产业化、新技术领域开拓等&#xff0c;都呈现节节攀升的局面。本文奖从产业变…

【1day】金和OA某接口存在未授权访问漏洞

注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录 一、漏洞描述 二、影响版本 三、资产测绘 四、漏洞复现

Adesk::Boolean CMultiEntityEx::subWorldDraw( AcGiWorldDraw* mode )什么情况下mode 为空

Adesk::Boolean CMultiEntityEx::subWorldDraw( AcGiWorldDraw* mode )什么情况下mode 为空 在AutoCAD的ObjectARX中,subWorldDraw是一个重要的虚拟函数,它被用来将对象的图形表示传递给绘图系统。当你创建一个自定义对象时,通常需要重写这个函数以提供对象的图形描述。 s…

Java项目学生管理系统一前后端环境搭建

在现代的软件开发中&#xff0c;学生管理系统是一个常见的应用场景。通过学生管理系统&#xff0c;学校能够方便地管理学生的信息、课程安排和成绩等数据。本文将介绍如何使用Java语言搭建一个学生管理系统的前后端环境&#xff0c;并提供一个简单的示例。 1.环境搭建 学生管…

vue开发,axios网络请求框架基本用法和封装

axios安装 npm install axiosaxios基本用法 默认的get请求&#xff0c;参数用params追加&#xff0c;多个参数通过json对象的方式&#xff0c;例如params:‘{type:“home”,page:1}’ axios({url: https://api.videolog.net.cn/baidu/token,params: }).then(value > {co…

为什么选择计算机

很久以前&#xff0c;有一个年轻人名叫艾登。他生活在一个充满奇妙魔法的世界里&#xff0c;但他总觉得自己缺少一种独特的能力&#xff0c;一种可以创造和改变世界的力量。 一天&#xff0c;艾登无意中进入了一座古老的图书馆&#xff0c;那里充满了尘封的书籍和神秘的氛围。…

WT588F02B-8S语音芯片助力破壁机:智能声音播放提示IC引领健康生活新潮流

在追求健康饮食的时代潮流中&#xff0c;破壁机作为榨汁、搅拌的重要厨房电器&#xff0c;融入智能技术的趋势不断加强。唯创知音的WT588F02B-8S语音芯片作为声音播放提示IC&#xff0c;为破壁机注入了更智能、便捷的声音提示功能&#xff0c;引领用户迈入健康生活的新潮流。 …