考虑一个ArrayList,在其中进行Iterator和List迭代器操作时,当迭代列表时,只要Collection对象发生变化,它就会引发ConcurrentModificationException,如下所示:
package JavaImpPrograms;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Wdfds {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Iterator it=list.iterator();
while(it.hasNext()){
Integer i= (Integer) it.next();
if(i%2==0)
list.remove(0);
}
System.out.println(list); } }
在更新Iterator对象时,情况并非如此:
while(it.hasNext()){
Integer i= (Integer) it.next();
if(i%2==0)
it.remove();
}
System.out.println(list); } }
当涉及到copyOnWriteArrayList时,如果使用正常迭代器的remove操作更新迭代器对象,如下所示(或),则listIterator更新(添加/删除),则抛出UnsupportedOperationException:
package JavaImpPrograms;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Wdfds {
public static void main(String[] args) {
List<Integer> list=new CopyOnWriteArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Iterator it=list.iterator();
while(it.hasNext()){
Integer i= (Integer) it.next();
if(i%2==0)
it.remove();
}
System.out.println(list); } }
package JavaImpPrograms;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class Wdfds {
public static void main(String[] args) {
List<Integer> list=new CopyOnWriteArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
ListIterator it=list.listIterator();
while(it.hasNext()){
Integer i= (Integer) it.next();
if(i%2==0)
it.add(9);
}
System.out.println(list); } }
我有几个与上述结果有关的问题:
1)对于ArrayList,如果迭代器能够在使用迭代器对象的迭代过程中修改列表,为什么copyOnWriteArrayList用于?
1)为什么copyOnWriteArrayList迭代器更新遇到迭代器对象更改时会引发unsupportedOperationExceptions,而集合对象发生更改时不会抛出异常?
3)上面两种情况看起来是彼此相反的。请让我知道它们何时使用以及在哪些情况下使用?
这完全令人困惑...
答案 0 :(得分:4)
您的问题全部由documentation of CopyOnWriteArrayList
回答:
ArrayList
的线程安全变体,其中所有可变操作(add
,set
等)都通过对基础数组进行全新复制来实现。
通过查看CopyOnWriteArrayList#iterator()
的文档可以发现
返回的迭代器在构造迭代器时提供列表状态的快照。遍历迭代器时不需要同步。迭代器不支持remove方法。
重要的是Iterator
仅提供列表的快照。
Iterator#remove()
要求以下行为:
从基础集合中移除此迭代器返回的最后一个元素(可选操作)。
由于iterator()
的{{1}}只是列表的快照,因此CopyOnWriteArrayList
看到的某些元素可能已经从列表中删除,因此(再次)可能将其删除引起麻烦(例如,当同一对象多次出现在列表中时)。唯一合乎逻辑的结果是通过抛出Iterator
来拒绝该操作。
答案 1 :(得分:1)
有两种类型的迭代器:“故障保护”和“故障快速”。迭代器快速失败,这意味着在遍历集合并尝试通过添加新元素来修改集合的结构时,会抛出 ConcurrentModificationException 。
要解决此问题,我们有 CopyOnWriteArrayList 是安全的,我们可以在遍历列表时添加元素。
很明显,当我们执行并发修改异常时 调用迭代器的next()函数。如果您想知道迭代器 检查修改,其实现存在于 定义了int变量modCount的AbstractList类。 modCount 提供更改列表大小的次数。 modCount 在每个next()调用中使用value来检查 函数checkForComodification()。
创建CopyOnWriteArrayList的目的是为了 安全迭代元素,即使底层列表得到 修改。
由于采用了复制机制,因此对 不允许返回迭代器–导致 UnsupportedOperationException。