Java集合类(十五)JUC中的集合--CopyOnWriteArraySet
2018-01-08 11:19
513 查看
一CopyOnWriteArraySet介绍
二CopyOnWriteArraySet原理和数据结构
三CopyOnWriteArraySet函数列表
四CopyOnWriteArraySet源码
和CopyOnWriteArrayList类似,CopyOnWriteArraySet具有以下特性:
它最适合于具有以下特征的应用程序:Set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
它是线程安全的。
因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。
迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。
使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
说明:
1. CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合。
2. CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。而CopyOnWriteArrayList本质是个动态数组队列,所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”! CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合。因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。
1. 添加
以add(E e)为例,来对“CopyOnWriteArraySet的添加操作”进行说明。下面是add(E e)的代码:
al 是CopyOnWriteArraySet的一个成员变量如下
CopyOnWriteArraySet的add操作,实际上是调用CopyOnWriteArrayList的addIfAbsent()方法
CopyOnWriteArraySet是通过CopyOnWriteArrayList实现的,它的API基本上都是通过调用CopyOnWriteArrayList的API来实现的。相信对CopyOnWriteArrayList了解的话,对CopyOnWriteArraySet的了解是水到渠成的事;所以,这里就不再对CopyOnWriteArraySet的代码进行详细的解析了。
二CopyOnWriteArraySet原理和数据结构
三CopyOnWriteArraySet函数列表
四CopyOnWriteArraySet源码
一、CopyOnWriteArraySet介绍
它是线程安全的无序的集合,可以将它理解成线程安全的HashSet。有意思的是,CopyOnWriteArraySet和HashSet虽然都继承于共同的父类AbstractSet;但是,HashSet是通过“散列表(HashMap)”实现的,而CopyOnWriteArraySet则是通过“动态数组(CopyOnWriteArrayList)”实现的,并不是散列表。和CopyOnWriteArrayList类似,CopyOnWriteArraySet具有以下特性:
它最适合于具有以下特征的应用程序:Set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
它是线程安全的。
因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。
迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。
使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
二、CopyOnWriteArraySet原理和数据结构
CopyOnWriteArraySet的数据结构,如下图所示:说明:
1. CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合。
2. CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的。而CopyOnWriteArrayList本质是个动态数组队列,所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”! CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合。因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。
三、CopyOnWriteArraySet函数列表
// 创建一个空 set。 CopyOnWriteArraySet() // 创建一个包含指定 collection 所有元素的 set。 CopyOnWriteArraySet(Collection<? extends E> c) // 如果指定元素并不存在于此 set 中,则添加它。 boolean add(E e) // 如果此 set 中没有指定 collection 中的所有元素,则将它们都添加到此 set 中。 boolean addAll(Collection<? extends E> c) // 移除此 set 中的所有元素。 void clear() // 如果此 set 包含指定元素,则返回 true。 boolean contains(Object o) // 如果此 set 包含指定 collection 的所有元素,则返回 true。 boolean containsAll(Collection<?> c) // 比较指定对象与此 set 的相等性。 boolean equals(Object o) // 如果此 set 不包含任何元素,则返回 true。 boolean isEmpty() // 返回按照元素添加顺序在此 set 中包含的元素上进行迭代的迭代器。 Iterator<E> iterator() // 如果指定元素存在于此 set 中,则将其移除。 boolean remove(Object o) // 移除此 set 中包含在指定 collection 中的所有元素。 boolean removeAll(Collection<?> c) // 仅保留此 set 中那些包含在指定 collection 中的元素。 boolean retainAll(Collection<?> c) // 返回此 set 中的元素数目。 int size() // 返回一个包含此 set 所有元素的数组。 Object[] toArray() // 返回一个包含此 set 所有元素的数组;返回数组的运行时类型是指定数组的类型。 <T> T[] toArray(T[] a)
四、CopyOnWriteArraySet源码
CopyOnWriteArraySet.java的完整源码如下:1. 添加
以add(E e)为例,来对“CopyOnWriteArraySet的添加操作”进行说明。下面是add(E e)的代码:
public boolean add(E e) { return al.addIfAbsent(e); }
al 是CopyOnWriteArraySet的一个成员变量如下
private final CopyOnWriteArrayList<E> al;
CopyOnWriteArraySet的add操作,实际上是调用CopyOnWriteArrayList的addIfAbsent()方法
// 添加元素(如果不存在)。 public boolean addIfAbsent(E e) { //获取数组元素 Object[] snapshot = getArray(); //判断元素在不在数组里,如果在的话返回false,否则调用addIfAbsent()方法 return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false : addIfAbsent(e, snapshot); }
// 将要添加的数组元素添加列表的尾部。 private boolean addIfAbsent(E e, Object[] snapshot) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] current = getArray(); int len = current.length; //判断两个数组是否相等(多线程访问时可能会改变数组) //线程在获取锁之前,可能对current 做了操作(增加、修改、删除) //current 是最新的数组,snapshot是旧的add()操作之前的数组 if (snapshot != current) { // Optimize for lost race to another addXXX operation int common = Math.min(snapshot.length, len); for (int i = 0; i < common; i++) if (current[i] != snapshot[i] && eq(e, current[i])) return false; //判断添加的元素在不在最新的数组里 if (indexOf(e, current, common, len) >= 0) return false; } Object[] newElements = Arrays.copyOf(current, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
CopyOnWriteArraySet是通过CopyOnWriteArrayList实现的,它的API基本上都是通过调用CopyOnWriteArrayList的API来实现的。相信对CopyOnWriteArrayList了解的话,对CopyOnWriteArraySet的了解是水到渠成的事;所以,这里就不再对CopyOnWriteArraySet的代码进行详细的解析了。
相关文章推荐
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- JUC集合---CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程”JUC”集合中的CopyOnWriteArraySet
- Java多线程系列--【JUC集合03】- CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- Java多线程系列--“JUC集合”03之 CopyOnWriteArraySet
- JUC集合-03之 CopyOnWriteArraySet
- java并发编程(二十一)----(JUC集合)CopyOnWriteArraySet和ConcurrentSkipListSet介绍
- 学学JUC(三)-- CopyOnWriteArrayList和CopyOnWriteArraySet
- Java concurrency集合之CopyOnWriteArraySet_动力节点Java学院整理
- 【JUC】JDK1.8源码分析之CopyOnWriteArraySet(七)
- 深入Java集合学习系列:深入CopyOnWriteArraySet
- Java常见集合框架(十一):Set之LinkedHashSet、CopyOnWriteArraySet
- Java集合--CopyOnWriteArraySet
- Java多线程 -- JUC包源码分析2 -- Copy On Write/CopyOnWriteArrayList/CopyOnWriteArraySet
- JUC源码分析24-队列-CopyOnWriteArrayList,CopyOnWriteArraySet