Skip to content

CopyOnWriteArraySet 源码分析

Published: at 11:20:15

简介

CopyOnWriteArraySet是一个基于CopyOnWriteArrayList实现的线程安全的Set集合,所以该Set和CopyOnWriteArrayList拥有完全相似的特性。

结构分析

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>();
}

其他方法

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的实现,所以没什么好分析的,总的来说功能很简单,就是依赖于CopyOnWriteArrayListaddIfAbsent方法来实现,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; // 遍历完后只需要校验长度是否一致即可
}

总结

  1. CopyOnWriteArraySet主要是基于CopyOnWriteArrayListaddIfAbsent方法实现的。
  2. CopyOnWriteArraySet是线程安全的有序集合。