2

考虑一个 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); } }

更新迭代器对象时不是这种情况,即如下所示:

 while(it.hasNext()){

            Integer i= (Integer) it.next();

            if(i%2==0)
            it.remove();            
            }

        System.out.println(list); } }

而当涉及到 copyOnWriteArrayList 时,如果迭代器对象被更新为像下面这样的普通迭代器的删除操作(或)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迭代器更新遇到Iterator对象变化时抛出unsupportedOperationExceptions,而collection对象发生变化时没有异常?

3)看起来上面2个场景是相反的。请告诉我这些什么时候使用以及在哪些场景中使用?

这完全令人困惑......

4

2 回答 2

4

您的问题都由以下文档CopyOnWriteArrayList回答:

一种线程安全的变体,ArrayList其中所有可变操作(addset等)都是通过制作底层数组的新副本来实现的。

查看文档CopyOnWriteArrayList#iterator()表明

返回的迭代器提供了构造迭代器时列表状态的快照。遍历迭代器时不需要同步。迭代器不支持 remove 方法。

重要的部分是Iterator仅提供列表的快照。

Iterator#remove()要求以下行为:

从基础集合中移除此迭代器返回的最后一个元素(可选操作)。

由于iterator()aCopyOnWriteArrayList只是列表的一个快照,某些被 a 看到的元素Iterator可能已经从列表中删除,因此(再次)删除它可能会导致麻烦(例如,当同一个对象多次出现在列表中时)。唯一合乎逻辑的结果是通过抛出UnsupportedOperationException.

于 2018-06-28T17:06:16.677 回答
1

有两种类型的迭代器 Fail Safe 和 Fail Fast。迭代器快速失败,这意味着当您遍历集合并尝试通过添加新元素来修改集合的结构时,会抛出ConcurrentModificationException

为了克服这个问题,我们有一个故障安全的CopyOnWriteArrayList,我们可以在遍历列表时添加元素。

很明显,当我们调用迭代器 next() 函数时,并发修改异常即将到来。如果您想知道 Iterator 如何检查修改,它的实现存在于 AbstractList 类中,其中定义了一个 int 变量 modCount。modCount 提供列表大小已更改的次数。modCount 值在每个 next() 调用中用于检查函数 checkForComodification() 中的任何修改。

创建 CopyOnWriteArrayList 是为了即使在底层列表被修改时也可以安全地迭代元素。

由于复制机制,不允许对返回的 Iterator 执行 remove() 操作 - 导致 UnsupportedOperationException。

http://www.baeldung.com/java-copy-on-write-arraylist

于 2018-06-28T17:11:22.990 回答