1. 简介
-
线程安全的无序的集合,可以将它理解成线程安全的HashSet
-
它最适合于具有以下特征的应用程序:Set 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
-
它是线程安全的。
-
因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove() 等等)的开销很大。
-
迭代器支持hasNext(), next()等不可变操作,但不支持可变 remove()等 操作。
-
使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
2.原理和数据结构
-
CopyOnWriteArraySet继承于AbstractSet,这就意味着它是一个集合
-
CopyOnWriteArraySet包含CopyOnWriteArrayList对象,它是通过CopyOnWriteArrayList实现的,而CopyOnWriteArrayList本质是个动态数组队列
-
所以CopyOnWriteArraySet相当于通过通过动态数组实现的“集合”!
-
CopyOnWriteArrayList中允许有重复的元素;但是,CopyOnWriteArraySet是一个集合,所以它不能有重复集合
-
因此,CopyOnWriteArrayList额外提供了addIfAbsent()和addAllAbsent()这两个添加元素的API,通过这些API来添加元素时,只有当元素不存在时才执行添加操作!
-
至于CopyOnWriteArraySet的“线程安全”机制,和CopyOnWriteArrayList一样,是通过volatile和互斥锁来实现的。
3.add方法
public boolean add(E e) {
//这个al就是CopyOnWriteArrayList也就是说CopyOnWriteArraySet内部是用CopyOnWriteArrayList来实现的
return al.addIfAbsent(e);
}
//这段代码也很好理解就是首先检查原来的数组里面有没有要添加的元素,如果有的话就不要再添加了,如果没有的话,创建一个新的数组,复制之前数组元素并且添加新的元素
public boolean addIfAbsent(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// Copy while checking if already present.
// This wins in the most common case where it is not present
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = new Object[len + 1];
for (int i = 0; i < len; ++i) {
if (eq(e, elements[i]))
return false; // exit, throwing away copy
else
newElements[i] = elements[i];
}
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
4.remove方法
//one foreach 遍历
for (Object o : list) {
System.out.println(o);
}
//two 迭代器的遍历
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
-
首先,说明一下CopyOnWriteArraySet的数据结构是什么?其实它的结构严格意义来说是一个集合,它的底层实现是利用数组,它的上层实现是CopyOnWriteArrayList。
-
其次,CopyOnWriteArraySet是一个集合,所以它是不可以放置重复的元素的,它的取重逻辑是在add中体现的。
-
最后,CopyOnWriteArraySet是利用CopyOnWriteArrayList来实现的,因为CopyOnWriteArrayList是线程安全的,所以CopyOnWriteArraySet操作也是线程安全的。