列表元素访问时的Java ConcurrentModificationException

时间:2017-03-27 23:31:59

标签: java list exception-handling concurrentmodification

如果我只想访问列表中的元素,有人可以向我解释为什么我会得到ConcurrentModificationException

我的印象是,只有当一个线程迭代一个集合而另一个线程试图修改它时,才会抛出ConcurrentModificationException。但这不是我的情况。我只是想得到一个列表元素。

这是一个代码片段,可以重现我的问题(请不要判断逻辑,我只是​​想重现这个问题):

private static void checkConcurrentModificationException(){

    List<String> stringSpan = new ArrayList<String>();
    List<List<String>> clausesStrings = new ArrayList<List<String>>();
    List<String> testStringList = new ArrayList<String>();

    for (int i = 0; i < 121; i++) {
        testStringList.add("abc");
    }

    for (int i = 0; i < testStringList.size(); i++) {
        stringSpan.clear();
        if (i%2==0) {
            if (i>3) {
                for (int j = i+1; j < testStringList.size(); j++) {
                    if (j>i+4 || j>=testStringList.size()-1) {
                        stringSpan = testStringList.subList(i, j); //might be the problem
                        clausesStrings.add(stringSpan);
                        break;
                    }
                }
            }
        } 
    }
    System.out.println("Clause list size: "+clausesStrings.size());
    System.out.println("First clause: "+clausesStrings.get(0));
}

我分析了说明并得出结论,问题出在stringSpan = testStringList.subList(i, j);,但我不太确定背后会发生什么以及它失败的原因。此外,我尝试将结果列表clausesStrings复制(不参考)到一个新列表但到目前为止没有运气。

1 个答案:

答案 0 :(得分:-3)

“我的印象是只有当一个线程迭代一个集合而另一个线程试图修改它时,才会抛出ConcurrentModificationException。”文档中没有任何内容说明仅在多线程场景中发生CME的任何事情。你是怎么得到这种印象的?

向我们提供异常消息的确切文本(复制粘贴)。

我怀疑stringSpan.clear();是你的罪魁祸首。 clear“从此列表中删除所有元素”,并且由于stringSpan是一个子列表,因此它将由您要迭代的列表支持。因此,当您迭代它时,您也会从testStringList中删除所有这些元素!巴姆! ConcurrentModificationException

编辑:

对于那些如此热切地低估我的答案的人:试试吧!

有效。当我运行OP的代码时,CME!当我做出建议的更改时,

run:
Clause list size: 58
First clause: [abc, abc, abc, abc, abc]
BUILD SUCCESSFUL (total time: 0 seconds)

没有CME!拿走那个,讨厌!

以下是代码:

public class SubModifier {
  static void checkConcurrentModificationException(){

    List<List<String>> clauses = new ArrayList<>();
    List<String> testItems = new ArrayList<>();

    for (int i = 0; i < 121; i++) {
      testItems.add("abc");
    }

    for (int i = 0; i < testItems.size(); i++) {
      if (i%2==0) {
        if (i>3) {
          for (int j = i+1; j < testItems.size(); j++) {
            if (j>i+4 || j>=testItems.size()-1) {
              List<String> span = testItems.subList(i, j);
              clauses.add(span);
              break;
            }
          }
        }
      } 
    }
    System.out.println("Clause list size: "+clauses.size());
    System.out.println("First clause: "+clauses.get(0));
  }

  public static void main(String[] args) {
    checkConcurrentModificationException();
  }
}