【问题标题】:Why doesn't my sample throw ConcurrentModificationException [duplicate]为什么我的示例不抛出 ConcurrentModificationException [重复]
【发布时间】:2015-09-01 04:13:19
【问题描述】:

我在测试ConcurrentModificationException 概念之后编写了这个示例:

public class Person
{
    String name;
    public Person(String name)
    {
        this.name = name;
    }
}

public static void main(String[] args)
{
    List<Person> l = new ArrayList<Person>();
    l.add(new Person("a"));
    l.add(new Person("b"));
    l.add(new Person("c"));

    int i  = 0;
    for(Person s : l)
    {
        if(s.name.equals("b"))
            l.remove(i);
        i++;
    }

    for(Person s : l)
        System.out.println(s.name);
}

当我执行上面的 main 方法时,ConcurrentModificationException 不会被抛出,输出控制台会打印以下结果:

a
c

根据我对这个问题的了解,在列表循环中,修改列表时,应该抛出 ConcurrentModificationException 异常。但是为什么在我的示例中没有出现这种情况?

【问题讨论】:

  • 没有保证对列表的结构修改会抛出ConcurrentModificationException
  • 可能是因为 ArrayList 的实现细节。阅读stackoverflow.com/questions/18448671/…
  • 因为您的循环在remove 之后立即退出。如果在“c”之后添加第 4 个元素或删除 Person“a”,则会出现异常。
  • @Marvin 指出了这种行为。

标签: java collections concurrentmodification


【解决方案1】:

没有保证对列表的结构修改会抛出ConcurrentModificationException

来自documentation

请注意,不能保证快速失败的行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的操作会尽最大努力抛出ConcurrentModificationException。因此,编写一个依赖此异常的正确性的程序是错误的:ConcurrentModificationException 应仅用于检测错误。

在这种特殊情况下,您是“幸运的”(或“不幸的”,具体取决于您的看法)。由于在执行另一次修改检查之前存在循环,因此结构变化未被注意到。

详细解释请参考dup中的答案:

【讨论】:

  • 我会犹豫是否将其视为答案...
  • @Marco13,你是什么意思?你能澄清一下吗?我的回答表明该行为符合合同。
  • 是的,但它没有以任何形式解释“为什么”。诚然,我也预料到它会抛出。例如,在列表中再添加一个人,然后它会抛出。为什么不针对此特定设置? (我目前正在调查这个......恕我直言,这是一个好问题)
  • 更新了我的答案。 (但是请注意,正式的答案需要 OP 还提供有关使用哪个运行时实现的详细信息,因为没有它,人们只能查看合同(javadoc)并推测实现。)
  • 好的,这确实是重复的,但是我正要发布与stackoverflow.com/a/14674151/3182664基本相同的内容(尽管它指的是特定的实现,但hasNext不会抛出但可能以引用列表的当前大小的方式实现是我在这里认为的“答案” - 恕我直言,没有冒犯)
猜你喜欢
  • 2011-08-29
  • 2014-09-11
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2014-06-05
  • 2018-01-05
  • 2014-08-24
  • 1970-01-01
相关资源
最近更新 更多