在Java中,如何在单线程程序中抛出ConcurrentModificationException?

时间:2011-02-19 16:15:44

标签: java concurrency concurrentmodification

我正在阅读这个“Freuqent Java concurrency problems”问题,并且在回答java.util.ConcurrentModificationException的答案时感到困惑。

我对答案的理解是,这可能发生在单线程程序中。 如何或什么条件导致以下代码抛出异常?

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
for (String string : list) { list.remove(string); }

3 个答案:

答案 0 :(得分:14)

此代码段总是抛出ConcurrentModificationException

规则如下:使用迭代器迭代时,您不能修改(添加或删除列表中的元素)(当您使用for-each循环时会发生这种情况)。

但是请注意,您可以使用Iterator.removeListIterator.add来通过迭代器修改列表(因为它知道修改,并且可以将其考虑在内)。

来自文档:

  

此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出一个ConcurrentModificationException。

concurrent 这个词指的是你在遍历期间修改列表

答案 1 :(得分:2)

您在循环播放列表时正在更改列表。

此处ConcurrentModificationException与线程无关。

警告!以下示例显示了在更改集合时如何使用集合可能会有危险。这不是OP的情况(通过迭代器和更改循环)

如果您使用带有这样的计数器的老式循环,我认为更容易想象它有什么问题:

List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));

for (int i = 0; i < list.size(); i++) { 
   list.remove(i);  //removes element at given index
} 

现在,第一次i为0,第0个元素被删除。第二次i为1,所以现在删除第一个元素。但是,在第一次移除之前,现在是第一个,曾经是第二个。那么,曾经是第一,现在是第0,永远不会被删除。

答案 2 :(得分:2)

因为您要从列表中删除并同时使用迭代器对其进行迭代。

使用迭代器查看等效代码。

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          String a=itr.next();
           list.remove(a);
      }
   }
}

正确的代码是

import java.lang.*;
import java.util.*;

class Test{
  public static void main(String[] argv){
      List<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c"));
      Iterator<String> itr=list.iterator();
      while(itr.hasNext()){
          itr.remove();
      }
   }
}