CopyOnWriteSet
  该容器与CopyOnWriteArrayList相似,也是读取时不加锁,任意线程可以读。写入时加锁创建一个新的容器,然后写入新元素。
  内部用CopyOnWriteArrayList存储元素
private final CopyOnWriteArrayList<E> al;
1.判断元素是否存在
直接遍历al中的数组,查看是否有相等元素。
这里可以看出该容器是可以存放null的。
**
* Returns {@code true} if this set contains the specified element.
* More formally, returns {@code true} if and only if this set
* contains an element {@code e} such that
* <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
*
* @param o element whose presence in this set is to be tested
* @return {@code true} if this set contains the specified element
*/
public boolean contains(Object o) {
return al.contains(o);
} -------------CopyOnWriteArrayList---------------------
/**
* Returns {@code true} if this list contains the specified element.
* More formally, returns {@code true} if and only if this list contains
* at least one element {@code e} such that
* <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return {@code true} if this list contains the specified element
*/
public boolean contains(Object o) {
Object[] elements = getArray();
return indexOf(o, elements, 0, elements.length) >= 0;
}
2.增加元素
 1 public boolean add(E e) {
2 return al.addIfAbsent(e);
3 }
4
5 -------------CopyOnWriteArrayList---------------------
6 public boolean addIfAbsent(E e) {
7 Object[] snapshot = getArray();
8 // 查找元素是否已经在数组中存在,如果存在则直接返回false,否则调用addIfAbsent(e, snapshot)
9 return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
10 addIfAbsent(e, snapshot);
11 }
12 /**
13 * A version of addIfAbsent using the strong hint that given
14 * recent snapshot does not contain e.
15 */
16 private boolean addIfAbsent(E e, Object[] snapshot) {
17 final ReentrantLock lock = this.lock;
18 lock.lock();
19 try {
20 Object[] current = getArray();
21 int len = current.length;
22 if (snapshot != current) {
23 // Optimize for lost race to another addXXX operation
24 int common = Math.min(snapshot.length, len);
25 for (int i = 0; i < common; i++)
26 if (current[i] != snapshot[i] && eq(e, current[i])) // 这里是判断common长度范围内是否有元素与e相等
27 return false;
28 if (indexOf(e, current, common, len) >= 0) // 这里是判断common长度范围外是否有元素与e相等
29 return false;
30 }
31 Object[] newElements = Arrays.copyOf(current, len + 1);
32 newElements[len] = e;
33 setArray(newElements);
34 return true;
35 } finally {
36 lock.unlock();
37 }
38 }
addIfAbsent(E e)方法内不直接lock然后进行判断。我的理解:是为了减少对性能的影响,对于已经set中已经存在该值的情况可以不加锁,只有不包含时才会进行同步。
 
3.删除元素
 1 public boolean remove(Object o) {
2 return al.remove(o);
3 }
4
5 -------------CopyOnWriteArrayList---------------------
6 public boolean remove(Object o) {
7 Object[] snapshot = getArray();
8 int index = indexOf(o, snapshot, 0, snapshot.length);
9 return (index < 0) ? false : remove(o, snapshot, index);
10 }
11 private boolean remove(Object o, Object[] snapshot, int index) {
12 final ReentrantLock lock = this.lock;
13 lock.lock();
14 try {
15 Object[] current = getArray();
16 int len = current.length;
17 // 如果当前CopyOnWriteArrayList对象al已经发生变化,则再次寻找索引
18 if (snapshot != current) findIndex: {
19 int prefix = Math.min(index, len);
20 // 从[0,prefix-1]区间内找是否存在o,找到则break
21 for (int i = 0; i < prefix; i++) {
22 if (current[i] != snapshot[i] && eq(o, current[i])) {
23 index = i;
24 break findIndex;
25 }
26 }
27 // 如果在[0,prefix -1]区间内没找到且index>=len,表示index超出当前长度,返回false
28 if (index >= len)
29 return false;
30 // 这部操作是有些时候对象al发生变化,但没影响对应index位置元素。这样可以省掉一次遍历操作。
31 if (current[index] == o)
32 break findIndex;
33 index = indexOf(o, current, index, len);
34 // 在[0,index-1],[index,index],[index,len-1]都没找到,返回false
35 if (index < 0)
36 return false;
37 }
38 Object[] newElements = new Object[len - 1];
39 System.arraycopy(current, 0, newElements, 0, index);
40 System.arraycopy(current, index + 1,
41 newElements, index,
42 len - index - 1);
43 setArray(newElements);
44 return true;
45 } finally {
46 lock.unlock();
47 }
48 }
  这里是直接判断是否在al中存在,不存在返回false,存在则执行al的删除操作。当然删除时也是加锁,然后再次进行是否存在的判断,并进行删除的逻辑操作。
不在remove(Object o)处加锁,而是宁愿后续再检测list是否发生变化,也是基于性能考虑。使得对存在的元素进行remove操作时不用加锁。

并发容器-CopyOnWriteSet的更多相关文章

  1. Java笔记(十六)并发容器

    并发容器 一.写时复制的List和Set CopyOnWrite即写时复制,或称写时拷贝,是解决并发问题的一种重要思路. 一)CopyOnWriteArrayList 该类实现了List接口,它的用法 ...

  2. Java多线程-并发容器

    Java多线程-并发容器 在Java1.5之后,通过几个并发容器类来改进同步容器类,同步容器类是通过将容器的状态串行访问,从而实现它们的线程安全的,这样做会消弱了并发性,当多个线程并发的竞争容器锁的时 ...

  3. JAVA 多线程随笔 (三) 多线程用到的并发容器 (ConcurrentHashMap,CopyOnWriteArrayList, CopyOnWriteArraySet)

    1.引言 在多线程的环境中,如果想要使用容器类,就需要注意所使用的容器类是否是线程安全的.在最早开始,人们一般都在使用同步容器(Vector,HashTable),其基本的原理,就是针对容器的每一个操 ...

  4. JAVA同步容器和并发容器

    同步容器类 同步容器类的创建 在早期的JDK中,有两种现成的实现,Vector和Hashtable,可以直接new对象获取: 在JDK1.2中,引入了同步封装类,可以由Collections.sync ...

  5. java并发:同步容器&并发容器

    第一节 同步容器.并发容器 1.简述同步容器与并发容器 在Java并发编程中,经常听到同步容器.并发容器之说,那什么是同步容器与并发容器呢?同步容器可以简单地理解为通过synchronized来实现同 ...

  6. Java面试题-并发容器和框架

    1. 如何让一段程序并发的执行,并最终汇总结果? 答:使用CyclicBarrier 和CountDownLatch都可以,使用CyclicBarrier 在多个关口处将多个线程执行结果汇总,Coun ...

  7. Java并发——同步容器与并发容器

    同步容器类 早期版本的JDK提供的同步容器类为Vector和Hashtable,JDK1.2 提供了Collections.synchronizedXxx等工程方法,将普通的容器继续包装.对每个共有方 ...

  8. Java并发编程:并发容器ConcurrentHashMap

    Java并发编程:并发容器之ConcurrentHashMap(转载) 下面这部分内容转载自: http://www.haogongju.net/art/2350374 JDK5中添加了新的concu ...

  9. Java 同步容器和并发容器

      同步容器(在并发下进行迭代的读和写时并不是线程安全的)   Vector.Stack.HashTable   Collections类的静态工厂方法创建的类(如Collections.synchr ...

随机推荐

  1. react第三方库

    作者:慕课网链接:https://www.zhihu.com/question/59073695/answer/1071631250来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  2. python 常用库收集

    读者您好.今天我将介绍20个属于我常用工具的Python库,我相信你看完之后也会觉得离不开它们.他们是: Requests.Kenneth Reitz写的最富盛名的http库.每个Python程序员都 ...

  3. 技术分享PPT整理(一):Bootstrap基础与应用

    最近在复习的时候总感觉有些知识点总结过,但是翻了一下博客没有找到,才想起来有一些内容是放在部门的技术分享里的,趁这个时候跳了几篇相对有价值的梳理一下,因为都是PPT,所以内容相对零散,以要点和图片为主 ...

  4. python多版本与虚拟环境

    这篇纯python技术文章,我自己平时也会用到,在此记录一下. 为什么会用到多个Python版本? 用macOS和Ubutntu的同学都知道系统默认安装的Python2.7.x,然后,我们平时pyth ...

  5. Centos7安装maven详情以及配置

    一.maven安装: 1.获取maven下载地址: 查询maven最新版本地址:https://maven.apache.org/download.cgi 当前最新版本为maven 3.6.3    ...

  6. KubeEdge云边协同设计原理

    云端组件CloudCore与k8s Master的关系 从黑盒角度看,CloudCore就是k8s的一个插件,它是非侵入的来扩展k8s的一部分功能,将原来云上的节点映射到边缘端进行管理,一个Cloud ...

  7. > 与 < 差在哪?-- Shell十三问<第十一问>

    > 与 < 差在哪?-- Shell十三问<第十一问> 谈到 I/O redirection ,不妨先让我们认识一下 File Descriptor (FD) .程序的运算,在 ...

  8. MongoDB教程--配置与入门

    MongoDB简介 阿里云配置MongoDB 数据库的增删查改 MongoDB 数据最重要的操作是Key-Value的映射.有了这样的映射,可以直接通过关键字去寻找想要的值.例如,通过用户的ID寻找与 ...

  9. [GDKOI2021] 提高组 Day 1 总结

    [ G D K O I 2021 ]    提 高 组    D a y   1    总 结 [GDKOI2021]~~ 提高组~~ Day~1~~ 总结 [GDKOI2021]  提高组  Day ...

  10. 2021年春软件工程"助教团队"成员介绍

    2021年春软件工程 助教团队 成员介绍 项目 内容 这个作业属于那个课程 2021春季学期软件工程(罗杰.任健) 这个作业的要求在哪里 团队介绍 姓名 照片 个人介绍 分工 刘Q 本团队的PM,和助 ...