2014-09-30 42 views
1

我得到一个ConcurrentModificationException CME,似乎不同于其他线程中要求的情况。我只运行一个线程。这是我的一段代码(编辑):ConcurrentModificationException:单线程,两个不同的哈希表

for(Type t : other.types.values()) { 
    types.put(t.getName(), t) 
} 

的CME在for语句时发生。 types的类型为Hashtable<String, Type>,并且是类型为Obj的对象中的非静态成员变量。 other也是类型Obj,并且代码段是Obj的方法的一部分。在for循环之前,我检查了thisother,this.typesother.types,以及this.types.values()other.types.values()是成对不同的对象。 (也可以在Eclipse调试器中通过不同的对象id进行验证)。

CME是可重现的。我不知道在这种情况下会发生什么。

@编辑:代码片段来自一个更大的工具,它实际上支持多线程。线程的数量是可控的,并且仅在选择单个线程时会发生此问题。同样在其方法中,代码被两个同步包围:一个在types上,另一个在other.types上。所以,我想,这不是一个线程问题。

该工具在Windows和Linux上运行。我们使用1.6兼容级别的Java 1.7。 (对不起,坏码,它不是我)

+1

我测试过了,我无法重现此行为,请在代码段中显示更多代码。顺便说一句,你怎么知道你只运行一个线程?你在使用任何库(Swing,GWT ...)吗?你在哪里运行(Windows,Android ...)? – m0skit0 2014-09-30 07:58:22

回答

0

如在ConcurrentModificationException的Javadoc指出:

此异常可能由已检测出的对象的并发修改方法被抛出当这样的修改是不允许的。 例如,一个线程在另一个线程遍历它时修改一个集合通常是不允许的。一般来说,在这些情况下迭代的结果是不确定的。某些迭代器实现(包括由JRE提供的所有通用集合实现的实现)可能会选择在检测到此行为时抛出此异常。这样做的迭代器被称为快速迭代器,因为它们快速且干净地失败,而在将来未定的时间冒着任意的,非确定性的行为冒险。

因为您正在使用foreach您实际上使用iterator来导航集合的元素。如果在创建迭代器后修改底层集合,通常Iterator的实现会抛出所提到的异常 - 在您的情况下,迭代器是集合上第一次迭代的创建者。这个问题是通过使用“经典”的循环可以避免的:

for(int i=0; i< other.types.values().size(); i++) { 
    types.put(t.getName(), t) 
} 

不过我相信你正在尝试所有元素添加从other.typestypes,对,你可以简单地做:

types.putAll(other.types) 

如果这两张是地图。

+0

您的解决方案绝对是明智的。但是他明确检查this.types!= other.types实际上应该避免并发修改,因为他不会更改基础集合。或者我错过了什么? – Chnoch 2014-09-30 08:18:51

+0

@Chnoch - 对不起,但我不认为我明白为什么显式检查会帮助修改并发异常。你能强调一下吗? – 2014-09-30 08:24:25

+0

因为他迭代other.types并将新项目添加到this.types。我看到它的方式other.types根本没有被修改。如果其他.types和类型是相同的引用,它将是显而易见的,但是由于他检查对象相等,它们应该是不同的HashMaps,因此如果他只是向类型添加新元素,则不会修改other.types。 – Chnoch 2014-09-30 08:26:55