访问列表元素时出现 Java ConcurrentModificationException

标签 java list exception 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 复制(没有引用)到一个新列表,但到目前为止没有成功。

最佳答案

“我的印象是 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)

没有芝加哥商品交易所!接受吧,仇恨者!

代码如下:

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();
  }
}

关于访问列表元素时出现 Java ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43058150/

相关文章:

java - 如何在迭代两个列表时检查字符串相等性?

java - Java 中 SQL 连接的问题

java - 如何将基元数组作为可变参数传递?

java - 如何为relativeLayout设置OnTouchListener?

java - 如何在 DSE 中使用 Java API 访问 Hive

java - 无法从异常继承

javascript - 条件 catch 子句 - 浏览器支持

java - 使用 swing 的动画管道

list - 打印 Erlang 列表中的每个元素

c++ - 在 C++ 中实现类型列表