简介
CopyOnWriteArraySet是一个基于CopyOnWriteArrayList实现的线程安全的Set集合,所以该Set和CopyOnWriteArrayList拥有完全相似的特性。
- 线程安全
- 可变操作(add、remove、set等)代价高,都是通过复制整个数组实现
- 迭代器不支持可变操作(add、remove、set),要防止遍历期间线程之间的干扰。
- 最适合集合大小保持较小,读操作大大超过可变操作的场景
结构分析
CopyOnWriteArraySet继承了AbstractSet,所以具有Set集合的功能,内部持有一个CopyOnWriteArrayList实例,作为数据底层的存储。
public class CopyOnWriteArraySet<E> extends AbstractSet<E>
implements java.io.Serializable {
private static final long serialVersionUID = 5457747651344034263L;
// 内部持有CopyOnWriteArrayList实例
private final CopyOnWriteArrayList<E> al;
...
}
方法分析
构造方法
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
- 构造方法就很简单了,就是初始化一个CopyOnWriteArrayList。
- CopyOnWriteArrayList的源码分析见上一篇。
其他方法
public boolean add(E e) {
return al.addIfAbsent(e);
}
public boolean addAll(Collection<? extends E> c) {
return al.addAllAbsent(c) > 0;
}
public boolean contains(Object o) {
return al.contains(o);
}
public void forEach(Consumer<? super E> action) {
al.forEach(action);
}
public Iterator<E> iterator() {
return al.iterator();
}
public boolean remove(Object o) {
return al.remove(o);
}
public void clear() {
al.clear();
}
public int size() {
return al.size();
}
其他方法都是调用的CopyOnWriteArrayList的实现,所以没什么好分析的,总的来说功能很简单,就是依赖于CopyOnWriteArrayList
的addIfAbsent
方法来实现,List本来是允许添加重复的数据的,但是CopyOnWriteArrayList
提供了一个addIfAbsent
方法来保证没有重复的数据,addIfAbsent
方法的源码分析可以查看上一篇文章CopyOnWriteArrayList
的源码分析。
equals方法
public boolean equals(Object o) {
if (o == this) // 引用相等
return true;
if (!(o instanceof Set)) // 比较的对象都不属于Set,没必要比下去了
return false;
Set<?> set = (Set<?>)(o);
// 拿到迭代器
Iterator<?> it = set.iterator();
// Uses O(n^2) algorithm that is only appropriate
// for small sets, which CopyOnWriteArraySets should be.
// Use a single snapshot of underlying array
// 当前对象的数组,以及数组长度
Object[] elements = al.getArray();
int len = elements.length;
// Mark matched elements to avoid re-checking
// 初始化一个长度一样的标识数组,用来记录标识另一个数组是否已经被校验过
boolean[] matched = new boolean[len];
int k = 0;
// 一次遍历
outer: while (it.hasNext()) {
if (++k > len) // 遍历发现两个集合长度都不一致
return false;
Object x = it.next();
for (int i = 0; i < len; ++i) {
// 遍历,比较,并记录下来标志位
if (!matched[i] && eq(x, elements[i])) {
matched[i] = true;
continue outer;
}
}
return false; //没匹配到未校验过的目标一致的值
}
return k == len; // 遍历完后只需要校验长度是否一致即可
}
总结
CopyOnWriteArraySet
主要是基于CopyOnWriteArrayList
的addIfAbsent
方法实现的。CopyOnWriteArraySet
是线程安全的有序集合。