java - 单线程 unmodifiableList 中的 ConcurrentModificationException

标签 java collections

我有一个单线程应用程序,它遍历一个巨大的树结构,子项存储在一个列表中。迭代器总是在不可修改的列表上运行:

public List<HierarchyNode> getChildren() {  
        return Collections.unmodifiableList(children);  
}  

我仍然在某个时候得到一个 ConcurrentModificationException,我认为这在不可修改的列表中是不可能的?迭代是使用访问者完成的...知道这是怎么可能的吗?

编辑:唯一可以修改此列表的是持有列表的类的构造函数:

private final List<HierarchyNode> children;

也许这与树的内存使用量相当大(>4GB)有关?

跟踪:

Testcase: testParserSingleFile(General.NetlistBuilder): Caused an ERROR
null
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
    at java.util.ArrayList$Itr.next(ArrayList.java:791)
    at java.util.Collections$UnmodifiableCollection$1.next(Collections.java:1067)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitArchitectureNode(HierarchyNodeVisitorImplementation.java:20)
    at com.bevm.semantics.netlist.NetlistBuilder.visitArchitectureNode(NetlistBuilder.java:40)
    at com.bevm.hierarchy.ArchitectureNode.accept(ArchitectureNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitEntityNode(HierarchyNodeVisitorImplementation.java:33)
    at com.bevm.semantics.netlist.NetlistBuilder.visitEntityNode(NetlistBuilder.java:33)
    at com.bevm.hierarchy.EntityNode.accept(EntityNode.java:33)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitComponentNode(HierarchyNodeVisitorImplementation.java:27)
    at com.bevm.hierarchy.ComponentNode.accept(ComponentNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitInstanceNode(HierarchyNodeVisitorImplementation.java:45)
    at com.bevm.semantics.netlist.NetlistBuilder.visitInstanceNode(NetlistBuilder.java:85)
    at com.bevm.hierarchy.InstanceNode.accept(InstanceNode.java:89)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitArchitectureNode(HierarchyNodeVisitorImplementation.java:21)
    at com.bevm.semantics.netlist.NetlistBuilder.visitArchitectureNode(NetlistBuilder.java:40)
    at com.bevm.hierarchy.ArchitectureNode.accept(ArchitectureNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitEntityNode(HierarchyNodeVisitorImplementation.java:33)
    at com.bevm.semantics.netlist.NetlistBuilder.visitEntityNode(NetlistBuilder.java:33)
    at com.bevm.hierarchy.EntityNode.accept(EntityNode.java:33)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitComponentNode(HierarchyNodeVisitorImplementation.java:27)
    at com.bevm.hierarchy.ComponentNode.accept(ComponentNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitInstanceNode(HierarchyNodeVisitorImplementation.java:45)
    at com.bevm.semantics.netlist.NetlistBuilder.visitInstanceNode(NetlistBuilder.java:85)
    at com.bevm.hierarchy.InstanceNode.accept(InstanceNode.java:89)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitArchitectureNode(HierarchyNodeVisitorImplementation.java:21)
    at com.bevm.semantics.netlist.NetlistBuilder.visitArchitectureNode(NetlistBuilder.java:40)
    at com.bevm.hierarchy.ArchitectureNode.accept(ArchitectureNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitEntityNode(HierarchyNodeVisitorImplementation.java:33)
    at com.bevm.semantics.netlist.NetlistBuilder.visitEntityNode(NetlistBuilder.java:33)
    at com.bevm.hierarchy.EntityNode.accept(EntityNode.java:33)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitComponentNode(HierarchyNodeVisitorImplementation.java:27)
    at com.bevm.hierarchy.ComponentNode.accept(ComponentNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitInstanceNode(HierarchyNodeVisitorImplementation.java:45)
    at com.bevm.semantics.netlist.NetlistBuilder.visitInstanceNode(NetlistBuilder.java:85)
    at com.bevm.hierarchy.InstanceNode.accept(InstanceNode.java:89)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitGenerateNode(HierarchyNodeVisitorImplementation.java:39)
    at com.bevm.semantics.netlist.NetlistBuilder.visitGenerateNode(NetlistBuilder.java:79)
    at com.bevm.hierarchy.GenerateNode.accept(GenerateNode.java:27)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitArchitectureNode(HierarchyNodeVisitorImplementation.java:21)
    at com.bevm.semantics.netlist.NetlistBuilder.visitArchitectureNode(NetlistBuilder.java:40)
    at com.bevm.hierarchy.ArchitectureNode.accept(ArchitectureNode.java:25)
    at com.bevm.hierarchy.HierarchyNodeVisitorImplementation.visitEntityNode(HierarchyNodeVisitorImplementation.java:33)
    at com.bevm.semantics.netlist.NetlistBuilder.visitEntityNode(NetlistBuilder.java:33)
    at com.bevm.hierarchy.EntityNode.accept(EntityNode.java:33)
    at com.beckhoff.vmagic.hierarchy.HierarchyNodeVisitorImplementation.visit(HierarchyNodeVisitorImplementation.java:15)
    at General.NetlistBuilder.testParserSingleFile(NetlistBuilder.java:125)

最佳答案

所以 Collection.unmodifiableList 并不是真正的线程安全的。这是因为它创建了底层 List 的不可修改 View 。但是,如果在迭代 View 时底层 List 被修改,您将获得 CME。请记住,CME 不需要由单独的线程引起。如果我执行以下操作,我将获得 CME:

 for (String e : myList){
     myList.remove(5); // throws CME
 }

更好的选择是Guava的ImmutableList这会创建传递列表的不可变副本。

为了澄清由于评论,将发布的代码替换为:

 public List<HierarchyNode> getChildren() {  
        return ImmutableList.copyOf(children);  
    }

从此方法返回的 List 保证永远不会抛出 CME。

更新:

如果您仍在尝试找出它在您的代码中出现的原因,请考虑以下几点:

  1. children 列表是否可以修改(我指的是传递给 unmodifiableList 的可修改 List)?
  2. 是否有任何调用 getChildren 的类曾经导致以可能更新列表的方式调用保存可修改列表的类?
  3. 或者是否有任何类获​​得多次使用的 Iterator 实例?

ImmutableList

关于java - 单线程 unmodifiableList 中的 ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13232657/

相关文章:

java - List<char[]> 中 char[] 的 String.valueOf() 行为

java - JPA的EntityManager是什么?

java: 不能在抽象类中使用构造函数

java - LinkedHashSet迭代不按升序排列?

kotlin - Kotlin-基于大小和时间的 block 序列

java - 如何在没有并发修改异常的情况下在for循环内将元素添加到java中的arraylist

java - DelayQueue 多个 take 调用

java - 按下主页按钮时 Android 应用程序崩溃但方向更改正常

java - 使用准备好的语句获取数据

java - 为什么缺少媒体类型 application/json 的编写器