Iterator,List迭代器和CopyOnWriteArrayList

时间:2018-06-28 16:58:00

标签: java collections java.util.concurrent listiterator copyonwritearraylist

考虑一个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)上面两种情况看起来是彼此相反的。请让我知道它们何时使用以及在哪些情况下使用?

这完全令人困惑...

2 个答案:

答案 0 :(得分:4)

您的问题全部由documentation of CopyOnWriteArrayList回答:

  

ArrayList的线程安全变体,其中所有可变操作(addset等)都通过对基础数组进行全新复制来实现。

通过查看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。

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