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操作时不用加锁。

最新文章

  1. windows环境下搭建vue+webpack的开发环境
  2. C# 使用网易邮箱发送邮件
  3. 长年承接AR图像识别项目,关于高速UnityARCam多图问题技术整理
  4. 配置VS使用winteracter
  5. SmartWiki开发日记之Laravel缓存扩展
  6. AutoCAD.NET二次开发:创建自定义菜单(AcCui)
  7. easyui获取日期datebox中的值
  8. Oracle触发器(trigger):view,schema,database
  9. cygwin org/apache/zookeeper/KeeperException
  10. linux 小技巧(磁盘空间搜索)
  11. LVS三种模式分析(超详细)
  12. Flask 系列之 优化项目结构
  13. HDU6216
  14. Linux上rsync配置
  15. mysql 建立索引的原则(转)
  16. 【转】Linux 高级的视角来查看Linux引导过程
  17. 摄像头驱动OV7725学习笔记连载(二):0V7725 SCCB时序的实现之寄存器配置
  18. php给$_POST赋值会导致值为空
  19. 【转】tcp_tw_recycle和tcp_timestamps导致connect失败问题
  20. Csharp 非安全代码

热门文章

  1. Linux系统(Centos7)最新版本Docker简易(yum)安装步骤
  2. validator库参数校验
  3. P1071 潜伏者(JAVA语言)
  4. Git本地操作2
  5. ASP.Net Core中处理异常的几种方法
  6. 11、Spring教程之声明式事务
  7. 远程拷贝文件--scp
  8. 面试准备——计算机网络(TCP的三次握手和四次挥手)
  9. 轻松理解 Spring AOP
  10. 自动化kolla-ansible部署ubuntu20.04+openstack-victoria之镜像制作centos7.8-15