单个Threaded unmodifiableList中的ConcurrentModificationException

Ben*_*rns 1 java collections

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

public List<HierarchyNode> getChildren() {  
        return Collections.unmodifiableList(children);  
}  
Run Code Online (Sandbox Code Playgroud)

我在某个时候仍然得到一个ConcurrentModificationException,我认为在一个不可修改的List中是不可能的?迭代是使用访问者完成的...任何想法如何可能?

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

private final List<HierarchyNode> children;
Run Code Online (Sandbox Code Playgroud)

也许这与thetree的内存使用量相当大(> 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)
Run Code Online (Sandbox Code Playgroud)

Joh*_*n B 10

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

 for (String e : myList){
     myList.remove(5); // throws CME
 }
Run Code Online (Sandbox Code Playgroud)

更好的选择是Guava的ImmutableList,它创建了传递列表的不可变副本.

有关评论的说明,请将发布的代码替换为:

 public List<HierarchyNode> getChildren() {  
        return ImmutableList.copyOf(children);  
    }
Run Code Online (Sandbox Code Playgroud)

List此方法返回的保证的广告到切勿将CME.

更新:

如果您仍在尝试弄清楚代码中的原因,请考虑以下事项:

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

ImmutableList

  • +1另一种解决方案是复制它.`return new ArrayList <HierarchyNode>(children); ` (2认同)