Java中的CopyOnWriteArrayList
Java中的CopyOnWriteArrayList是List接口的线程安全实现。
在Java 1.5和Collections框架的一部分中添加了CopyOnWriteArrayList。
Java ArrayList和ConcurrentModificationException
ArrayList是List接口的基本实现之一,并且是Java Collections Framework的一部分。
我们可以使用迭代器遍历ArrayList元素。
我们来看一下ArrayList的示例程序。
ConcurrentListExample.java
package com.theitroad.collections; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class ConcurrentListExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); //get the iterator Iterator<String> it = list.iterator(); //manipulate list while iterating while(it.hasNext()){ System.out.println("list is:"+list); String str = it.next(); System.out.println(str); if(str.equals("2"))list.remove("5"); if(str.equals("3"))list.add("3 found"); //below code don't throw ConcurrentModificationException //because it doesn't change modCount variable of list if(str.equals("4")) list.set(1, "4"); } } }
当我们在上面的程序上运行时,只要修改ArrayList就会得到java.util.ConcurrentModificationException。
发生这种情况是因为ArrayList迭代器在设计上是快速失败的。
这意味着一旦创建了迭代器,如果修改了ArrayList,它将引发ConcurrentModificationException。
如果检查控制台日志,则会注意到Iteratornext()
方法引发了异常。
如果您查看ArrayList源代码,则每次我们在引发异常的迭代器上调用next()时,都会调用以下方法。
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
这里的modCount是保存修改次数的ArrayList变量,每当我们使用add,remove或者trimToSize方法时,它都会递增。
" expectedModCount"是迭代器变量,当我们创建与" modCount"具有相同值的迭代器时会初始化该变量。
这就解释了为什么我们使用set
方法替换任何现有元素时不会得到异常。
因此,基本上,如果列表大小更改,则迭代器将抛出" ConcurrentModificationException"。
Java中的CopyOnWriteArrayList
有时,如果我们找到一些特定的元素,我们希望从列表中添加或者删除元素,在这种情况下,我们应该使用并发集合类– CopyOnWriteArrayList。
这是java.util.ArrayList的线程安全变体,其中所有可变操作(添加,设置等)都通过对基础数组进行全新复制来实现。
CopyOnWriteArrayList给处理带来了另外的重载,但是当修改量比遍历操作数少时,它非常有效。
如果将实现更改为" CopyOnWriteArrayList",则不会发生任何异常,下面是生成的输出。
list is:[1, 2, 3, 4, 5] 1 list is:[1, 2, 3, 4, 5] 2 list is:[1, 2, 3, 4] 3 list is:[1, 2, 3, 4, 3 found] 4 list is:[1, 4, 3, 4, 3 found] 5
请注意,它允许修改列表,但它不会更改迭代器,并且我们得到的元素与原始列表中的元素相同。