【问题标题】:Difference between Iterator,List iterator and CopyOnWriteArrayList迭代器、列表迭代器和 CopyOnWriteArrayList 的区别
【发布时间】:2018-06-28 16:58:00
【问题描述】:

考虑一个 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 时,如果迭代器对象被更新为像下面这样的普通迭代器的删除操作(或)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) 上面两个场景好像是对立的,请告诉我这些是什么时候用在什么场景下的?

真是一头雾水……

【问题讨论】:

  • 请正确格式化您的代码。

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


【解决方案1】:

documentation of CopyOnWriteArrayList为您解答所有问题:

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

查看CopyOnWriteArrayList#iterator() 的文档会发现

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

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

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

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

由于CopyOnWriteArrayListiterator() 只是列表的快照,Iterator 看到的某些元素可能已经从列表中删除,因此(再次)删除它可能会导致问题(例如,当同一对象多次出现在列表中)。唯一合乎逻辑的结果是通过抛出 UnsupportedOperationException 来拒绝操作。

【讨论】:

    【解决方案2】:

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

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

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

    创建 CopyOnWriteArrayList 是为了允许 即使底层列表获取,也可以安全地迭代元素 修改。

    由于复制机制,remove() 操作在 不允许返回的迭代器——结果是 UnsupportedOperationException。

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

    【讨论】:

    • 但是为什么 CopyOnWriteArrayList 会抛出 Iterator 对象更新异常?
    • 创建 CopyOnWriteArrayList 是为了允许安全地迭代元素,即使基础列表被修改。由于复制机制,不允许对返回的 Iterator 执行 remove() 操作 - 导致 UnsupportedOperationException: baeldung.com/java-copy-on-write-arraylist
    猜你喜欢
    • 2012-10-11
    • 2018-01-28
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 1970-01-01
    相关资源
    最近更新 更多