1. 简介
在 List
中,存在 CopyOnWriteArrayList
,其特点是在对List
进去修改,都是加锁后将旧数组的元素拷贝到一个新数组进行操作。而 CopyOnWriteArraySet
的底层则是使用 CopyOnWriteArrayList
进行实现的。
2. 深入源码
private final CopyOnWriteArrayList<E> al;
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
public CopyOnWriteArraySet(Collection<? extends E> c) {
if (c.getClass() == CopyOnWriteArraySet.class) {
@SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
(CopyOnWriteArraySet<E>)c;
al = new CopyOnWriteArrayList<E>(cc.al);
}
else {
al = new CopyOnWriteArrayList<E>();
al.addAllAbsent(c);
}
}
可以看到CopyOnWriteArraySet
就是通过CopyOnWriteArrayList
实现的。
我们知道,CopyOnWriteArrayList
并不能保证元素是不重复的,那么CopyOnWriteArraySet
是如何保证元素是不重复的?
public boolean add(E e) {
return al.addIfAbsent(e);
}
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();
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;
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
在添加元素时,首先遍历数组中的元素有没有被添加,如果没有被添加则将该元素加入数组,否则,并不重复添加。
总结
(1)CopyOnWriteArraySet
并不是使用Map实现的,而是用CopyOnWriteArrayList
实现的;
(2)其具有 CopyOnWriteArrayList
的特性,对写操作阻塞,读操作不阻塞。