您的位置:首页 > 编程语言 > Java开发

《java.util.concurrent 包源码阅读》08 CopyOnWriteArrayList和CopyOnWriteArraySet

2014-08-12 14:36 519 查看
CopyOnWriteArrayList和CopyOnWriteArraySet从数据结构类型上来说是类似的,都是用数组实现的保存一组数据的数据结构,区别也简单就是List和set的区别。因此这里就先讨论CopyOnWriteArrayList,然后再说CopyOnWriteArraySet。

这里重点关注的是CopyOnWrite,从字面上很容易理解,每当写操作的时候复制存储数据的数组,把拷贝上修改完再覆盖原先的数组。那么这样的数据结构适用的情况必然是读操作占绝大多数(很少进行写操作),且数据量不大的场合(例如黑名单)。

因此再来看CopyOnWriteArrayList的实现就很好理解了,必然会有一个volatile的数组,一把锁用于写操作(读操作的时候是不要锁的)。

/** The lock protecting all mutators */
transient final ReentrantLock lock = new ReentrantLock();

/** The array, accessed only via getArray/setArray. */
private volatile transient Object[] array;


复制整个数组使用Arrays.copyOf,部分复制数组使用System.arraycopy。下面以add方法为例:

public void add(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
if (index > len || index < 0)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+len);
Object[] newElements;
int numMoved = len - index;
if (numMoved == 0)
newElements = Arrays.copyOf(elements, len + 1);
else {
newElements = new Object[len + 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index, newElements, index + 1,
numMoved);
}
newElements[index] = element;
setArray(newElements);
} finally {
lock.unlock();
}
}


可以看到如果在最后添加元素,则使用Arrays.copyOf新建并复制整个数组,如果在中间插入,则使用System.arraycopy分两段复制,然后插入元素。setArray方法的作用就是覆盖原来的数组,代码如下:

final void setArray(Object[] a) {
array = a;
}


下面来简单谈谈CopyOnWriteArraySet,其实CopyOnWriteArraySet就是一个CopyOnWriteArrayList的包装类:

private final CopyOnWriteArrayList<E> al;


区别在于因为Set不允许重复元素,因此CopyOnWriteArraySet的add方法调用的是CopyOnWriteArrayList的addIfAbsent方法

public boolean add(E e) {
return al.addIfAbsent(e);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐