正文
;
startIteratorThread(list);
startModifyThread(list);
}
不过,需要说明的是,
CopyOnWriteArrayList的迭代器不支持修改操作,也不支持一些依赖迭代器修改方法的操作,比如Collections的sort方法
,看个例子:
public static void sort(){
CopyOnWriteArrayList
list = new CopyOnWriteArrayList();
list.add("c");
list.add("a");
list.add("b");
Collections.sort(list);
}
执行这段代码会抛出异常:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.concurrent.CopyOnWriteArrayList$COWIterator.set(CopyOnWriteArrayList.java:1049)
at java.util.Collections.sort(Collections.java:159)
为什么呢?因为Collections.sort方法依赖迭代器的set方法,其代码为:
public static
> void sort(List
list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator
i = list.listIterator();
for (int j=0; j
i.next();
i.set((T)a[j])
;
}
}
基于synchronized的同步容器的另一个问题是复合操作,比如先检查再更新,也需要调用方加锁,而CopyOnWriteArrayList直接支持两个原子方法:
//不存在才添加,如果添加了,返回true,否则返回false
public boolean addIfAbsent(E e)
//批量添加c中的非重复元素,不存在才添加,返回实际添加的个数
public int addAllAbsent(Collection extends E> c)
基本原理
CopyOnWriteArrayList的内部也是一个数组,但这个数组是以原子方式被整体更新的。每次修改操作,都会新建一个数组,复制原数组的内容到新数组,在新数组上进行需要的修改,然后以原子方式设置内部的数组引用,这就是写时拷贝。
所有的读操作,都是先拿到当前引用的数组,然后直接访问该数组,在读的过程中,可能内部的数组引用已经被修改了,但不会影响读操作,它依旧访问原数组内容。
换句话说,数组内容是只读的,写操作都是通过新建数组,然后原子性的修改数组引用来实现的。我们通过代码具体来看下。
内部数组声明为: