jdk 5的concurrent包中,添加了几个CopyOnWrite开头的类,包括CopyOnWriteHashMap,CopyOnWriteArrayList,CopyOnWriteArraySet。 copy-on-write模式声明了,为了维护对象的一致性快照,要依靠不可变性(immutability)来消除在协调读取不同的但是相关的属性时需要的同步。对于集合,这意味着如果有大量的读(即 get()
) 和迭代,不必同步操作以照顾偶尔的写(即 add()
)调用。对于新的 CopyOnWriteArrayList
和 CopyOnWriteArraySet
类,所有可变的(mutable)操作都首先取得后台数组的副本,对副本进行更改,然后替换副本。这种做法保证了在遍历自身更改的集合时,永远不会抛出 ConcurrentModificationException
。遍历集合会用原来的集合完成,而在以后的操作中使用更新后的集合。这些新的集合, CopyOnWriteArrayList
和 CopyOnWriteArraySet
,最适合于读操作通常大大超过写操作的情况。
如下所示,集合的使用与它们的非 copy-on-write 替代物完全一样。只是创建集合并在其中加入或者删除元素。即使对象加入到了集合中,原来的 Iterator
也可以进行,继续遍历原来集合中的项。
import java.util.*;
import java.util.concurrent.*;
public class CopyOnWrite {
public static void main(String args[]) {
List list1 = new CopyOnWriteArrayList(Arrays.asList(args));
List list2 = new ArrayList(Arrays.asList(args));
Iterator itor1 = list1.iterator();
Iterator itor2 = list2.iterator();
list1.add("New");
list2.add("New");
try {
printAll(itor1);
} catch (ConcurrentModificationException e) {
System.err.println("Shouldn't get here");
}
try {
printAll(itor2);
} catch (ConcurrentModificationException e) {
System.err.println("Will get here.");
}
}
private static void printAll(Iterator itor) {
while (itor.hasNext()) {
System.out.println(itor.next());
}
}
}
这个示例程序用命令行参数创建 CopyOnWriteArrayList
和 ArrayList
这两个实例。在得到每一个实例的 Iterator
后,分别在其中加入一个元素。当 ArrayList
迭代因一个 ConcurrentModificationException
问题而立即停止时, CopyOnWriteArrayList
迭代可以继续,不会抛出异常,因为原来的集合是在得到 iterator 之后改变的。如果这种行为(比如通知原来一组事件监听器中的所有元素)是您需要的,那么最好使用 copy-on-write 集合。如果不使用的话,就还用原来的,并保证在出现异常时对它进行处理。
[1].驯服 Tiger: 并发集合 http://www.ibm.com/developerworks/cn/java/j-tiger06164/