ConcurrentModificationException,需要澄清

时间:2011-08-30 18:47:24

标签: java concurrency concurrentmodification

以下模型代码最终在ConcurrentModificationException中发生(正如我理解的那样),因为我正在迭代一个我正在修改的集合。

Set<String> data = new HashSet<String>();
data.add("a=1");
data.add("b=2");
data.add("c=3");
data.add("d=4");

for (String s : data) {
    data.remove(s);
}

但为什么呢?请帮助澄清

4 个答案:

答案 0 :(得分:2)

抛出异常只是因为你在迭代它时修改了集合(通过调用data.remove(s))。 Java Collections通常要求在迭代它们的值时不能修改它们。

来自official documentation

  

一个线程通常不允许修改Collection,而另一个线程正在迭代它。通常,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。执行此操作的迭代器称为失败快速迭代器,因为它们快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。

答案 1 :(得分:2)

您违反了迭代器的合同 。来自ConcurrentModificationException javadoc

  

如果单个线程发出一系列方法调用   违反对象的合同,对象可能抛出这个   例外。例如,如果线程直接修改集合   而它使用快速失败的迭代器迭代集合,   迭代器将抛出此异常。

答案 2 :(得分:1)

您必须使用Iterator从Set

中删除元素

答案 3 :(得分:1)

这是因为编译器实际上插入了Iterator,然后使用传统的for循环迭代元素。如果修改迭代器所在的Collection,则会导致未确定的行为。为了防止这种情况,抛出ConcurrentModificationException

另见here

  

项目7.不要在迭代期间修改列表。虽然for-each语法不提供对等效基本for循环使用的迭代器的直接访问,但可以通过直接调用列表中的其他方法来修改列表。这样做可能会导致不确定的程序行为。特别是,如果对iterator()的编译器插入调用返回一个故障快速迭代器,则可能抛出java.util.ConcurrentModificationException运行时异常。但这只是尽力而为,除非作为在异常被抛出时检测错误的手段,否则不能依赖它。

Language Specification中每个循环的部分。