首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >矢量方法、迭代器和ListIterator快速失败的原因

矢量方法、迭代器和ListIterator快速失败的原因
EN

Stack Overflow用户
提问于 2010-12-18 18:57:44
回答 3查看 6.6K关注 0票数 3

根据http://download.oracle.com/javase/1.4.2/docs/api/java/util/Vector.html

向量的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建iterator之后的任何时候对向量进行了结构上的修改,那么除了通过Iterator自己的remove或add方法,Iterator将抛出一个ConcurrentModificationException。因此,在并发修改的情况下,迭代器迅速而干净地失败,而不是在未来一个未定的时间冒着任意的、不确定的行为的风险。向量元素方法返回的数字不会失败。请注意,迭代器的快速失败行为不能保证,一般来说,在不同步并发修改的情况下不可能提供任何硬的保证。快速失败的迭代器在最大努力的基础上将ConcurrentModificationException抛出。因此,编写依赖于此异常的程序是错误的:迭代器的快速失败行为应该只用于检测bug。

,你能给我一个例子来验证上面的一组语句吗?我还不清楚向量的方法Iterator和ListIterator的快速失效行为。?困惑:-(

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-12-18 19:01:17

--如果在创建Iterator之后的任何时候对向量进行结构修改,则除通过Iterator自己的remove或add方法外,Iterator将抛出一个ConcurrentModificationException

下面是一个示例:

代码语言:javascript
复制
import java.util.*;

public class Test {

    public static void main(String[] args) {
        List<String> strings = new Vector<String>();

        strings.add("lorem");
        strings.add("ipsum");
        strings.add("dolor");
        strings.add("sit");

        int i = 0;

        Iterator<String> iter = strings.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());

            // Modify the list in the middle of iteration.
            if (i++ == 1)
                strings.remove(0);
        }
    }
}

输出:

代码语言:javascript
复制
lorem
ipsum
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at Test.main(Test.java:18)

该方案做了以下工作:

twice.

  • Modifies

  • 创建向量,并获取迭代器

  • 调用向量(通过再次移除第一个next() next() (在向量已为modified)

  • This之后),从而引发ConcurrentModificationException

由于Java的for-每个循环依赖于迭代器,这些构造也可能抛出ConcurrentModificationExceptions。解决方案是在迭代之前创建列表的副本(因此您可以在副本上进行迭代),或者例如使用这样的CopyOnWriteArrayList

代码语言:javascript
复制
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class Test {

    public static void main(String[] args) {
        List<String> strings = new CopyOnWriteArrayList<String>();

        strings.add("lorem");
        strings.add("ipsum");
        strings.add("dolor");
        strings.add("sit");

        int i = 0;

        Iterator<String> iter = strings.iterator();
        while (iter.hasNext()) {
            System.out.println(iter.next());

            // Modify the list in the middle of iteration.
            if (i++ == 1)
                strings.remove(0);
        }
    }
}

输出:

代码语言:javascript
复制
lorem
ipsum
dolor
sit
票数 8
EN

Stack Overflow用户

发布于 2010-12-18 19:02:05

触发并发修改异常的一种简单方法是

代码语言:javascript
复制
List<String> strings = new ArrayList<String>();
strings.add("a");
strings.add("b");
for(String s: strings)
  strings.remove(s);

这会触发异常,因为集合在集合上的迭代过程中会更改集合。

Iterator快速失败的原因是帮助您检测一个集合是并发修改的(这些集合不支持),并帮助检测错误发生的位置。如果它没有这个特性,那么您可能会有一些微妙的bug,这些bug可能直到您的代码后面很久才会出现问题。(使他们更难比赛)

较新的并发集合处理并发修改的方式不同,一般不会这样做。它们是在2004年引入核心Java的,我建议您看看这些新的集合。

顺便说一句:除非你必须使用向量,否则不要使用矢量。

票数 2
EN

Stack Overflow用户

发布于 2010-12-18 19:26:11

假设您有一个包含1-10的整数向量,并且要删除奇数。您在此列表上迭代,查找赔率,并使用迭代器remove()方法。在此之后,您有一些代码,当然,假设向量中没有奇数。如果另一个线程在此过程中修改向量,有时可能会出现奇数(取决于竞争条件),从而破坏后面的代码。也许它甚至不会马上崩溃;也许它直到几个小时或几天后才会产生问题--很难排除故障。这就是elements()方法所发生的事情。

快速故障意味着一旦出现这个(潜在的)问题并发出警报,这将使故障诊断变得容易得多。一旦发现另一个线程修改了集合,就会引发异常。迭代器就是这样发生的。

iterator()listIterator()返回的迭代器积极监视对基础列表的意外修改。向量类(实际上是它的父AbstractList)每次修改计数器时都会增加一个计数器。当为向量创建迭代器时,它们会存储向量修改计数器的副本。每次调用next()remove()时,Iterator都会将计数器的存储值与向量的实际计数器进行比较。如果它们不同,就会抛出一个ConcurrentModificationException。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4479554

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档