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. 叫练手把手教你读JVM之GC信息

    案例 众所周知,GC主要回收的是堆内存,堆内存中包含年轻代和老年代,年轻代分为Eden和Surivor,如下图所示.我们用案例分析下堆的GC信息[版本:HotSpot JDK1.8]. /** * @ ...

  2. The 2018 ACM-ICPC CCPC NING XIA G-Factories

    题意:在一棵数的叶子上建k个工厂保证,求两两距离之和的最小值. 思路:如果一个一个叶子节点去考虑去与否太麻烦了,直接考虑该节点的子树上选取几个作为工厂,利用树形DP,dp[u][i]表示的是u节点为根 ...

  3. C语言数组寻址

    C语言数组 数组的定义 数组是用来存放数据类型相同且逻辑意义相同的数据 数组的大小 数组的大小不能是变量,必须是常量或者常量表达式,常量表达式由编译器编译时自动求值. 也可以不指定数组大小,但必须对数 ...

  4. Ubuntu18.04美化(Mac OS主题) 美化小白专用

    本文主要针对第一次接触Ubuntu美化的童鞋们,有些啰嗦的地方大神勿喷 先上效果图 首先安装神器 gnome-tweak-tool 开启一个终端,输入 sudo apt install gnome-t ...

  5. PHP并发抢购解决方案

    Mysql版 逻辑步骤 mysql存储引擎使用Innodb 开始事务,查询商品库存并加上共享锁 判断库存是否足够,进行商品/订单/用户等操作 提交事务,完成下单抢购 代码参考 // 关闭自动提交 $t ...

  6. springboot的yml中的bruid没有提示

    解决方案: springboot的yml中的bruid没有提示只要在maven加上:druid-spring-boot-starter(注意版本的统一,否则可能会冲突) 效果图:

  7. 【工程应用一】 多目标多角度的快速模板匹配算法(基于NCC,效果无限接近Halcon中........)

    愿意写代码的人一般都不太愿意去写文章,因为代码方面的艺术和文字中的美学往往很难兼得,两者都兼得的人通常都已经被西方极乐世界所收罗,我也是只喜欢写代码,让那些字母组成美妙的歌曲,然后自我沉浸在其中自得其 ...

  8. 80%的人都不会的,15个Linux实用技巧

    熟悉 Linux 系统的同学都知道,它高效主要体现在命令行.通过命令行,可以将很多简单的命令,通过自由的组合,得到非常强大的功能. 命令行也就意味着可以自动化,自动化会使你的工作更高效,释放很多手工操 ...

  9. 【Django学习笔记】-环境搭建

    对于初学django新手,根据以下步骤可以快速进行Django环境搭建 虚拟环境创建 使用virtualenv创建并启用虚拟机环境 ,关于virtualenv可参考https://www.yuque. ...

  10. spring-cloud-consul 服务注册发现与配置

    下面是 Spring Cloud 支持的服务发现软件以及特性对比(Eureka 已停止更新,取而代之的是 Consul): Feature euerka Consul zookeeper etcd 服 ...