概述
CopyOnWriteArrayList, CopyOnWriteArraySet这两个容器类是从java1.5开始加入的java.util.concurrent包的。其中与HashSet类似的CopyOnWriteArraySet内部也是直接使用的CopyOnWriteArrayList,所以本文着重介绍CopyOnWriteArrayList(简称COW)的原理。
CopyOnWriteArrayList是一个很好用的并发容器,内部还是和ArraList一样使用的数组结构来实现,所以在查询上面有着很高的效率,同时就和它的名字一样,是一个在写的时候copy,意思是在进行写操作的时候先copy一个一样的数组在这个数组上进行写操作之后随即将新的数组赋值回去。这样就使得并发环境下不会存在同时对数组写产生的问题。
源码分析
类定义
源码:
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
很常规的还是实现了List接口,同时实现了RandomAccess,Cloneable和Serializable接口表示COW支持快速随机访问,克隆和序列化。
关键属性
final transient ReentrantLock lock = new ReentrantLock();
private transient volatile Object[] array;
COW中没有什么繁杂的属性定义,其中array属性用来存放数据元素,同时使用了volatile关键字来修饰,意味着在对array的读/写(仅仅是读和写,不包含复合操作,可以参考volatile的语义)是符合原子性的。同时使用了重入锁来作为写操作的时候做锁。
构造方法
COW提供了三种构造方法,相对来说都比较常规,但是值得注意的是当使用无参的构造方法的时候是直接new一个长度为0的数组作为容器,这就意味着当我们往COW里面添加元素的时候,因为数组是定长的,所以会去创建新的数组,虽然所有的写操作都会有这个操作,但是对于初始化的时候来说直接用无参构造器来初始化是相对开销很大的。
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
if (c.getClass() == CopyOnWriteArrayList.class)
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
elements = c.toArray();
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elements.getClass() != Object[].class)
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
setArray(eleme