2013-02-25 34 views
1

如果我同时修改一个Java集,我会得到一个ConcurrentModificationException。问题是堆栈跟踪表明在某个Map迭代器上遇到了修改。我现在明白,Maps是用来在java中实现Sets的,但这些细节在实现中是内部的。我相信内部的Map迭代器异常应该已经被适当地包装在一个应该被传回的Set Iterator相关异常中。为什么Java集转储堆栈上的ConcurrentModificationException异常有关Map迭代器?

我有意义还是我错过了什么?我花了两天的时间试图在代码中发现不存在的错误的Map操作,最终偶然发现了导致问题的Set操作(通过反复试验,而不是逻辑过程或文档)。我想知道我将来如何避免这种挫折。

----------- UPDATE -------------- 我的查询不是关于如何获得并发权。我的查询是如何避免被无用的堆栈跟踪消息误导。 Map迭代器异常没有业务出现在堆栈跟踪中,而不是实际的SetIterator异常,这从用户的角度来看是有意义的

回答

0

ConcurrentModificationException在迭代集合并且另一个线程尝试修改它时发生;或相反亦然。我理解你的观点,但是一个简单的解决方法是简单地用布尔标志来表示集合正在被迭代。这样,您的修改线程可以简单地等待该标志变为假,并且您的线程永远不会有这样的冲突:)

+0

克里斯,我明白为什么抛出异常。我担心的是,stack-trace将异常与Map迭代器关联,而不是Set迭代器,因为内部集合是使用java中的Maps实现的。我的问题是如何避免这种堆栈痕迹导致的误导 – 2013-02-25 07:58:00

0

您可以使用允许并发修改的Set。像ConcurrentSkipListSet或CopyOnWriteArraySet一样,Google Guava还有其他获取并发集的方法。

1

虽然它在表面看起来有点奇怪,但当出现这样的错误时,堆栈跟踪应该会提供所需的信息 - 忽略java.util内部的跟踪的前几行并查找第一行参考你自己的一个类。这条线将成为您调试时开始寻找的地方。

至于为什么迭代器在HashSet似乎是一个地图相关,而不是一组相关的类型,这是因为它是 - 的HashSet.iterator的实现只返回backingMap.keySet().iterator()。没有像这样的“SetIterator”。

+0

嗯,我的意思是堆栈跟踪中应该有一个跟踪步骤;例如: at java.util.HashMap $ KeyIterator.next(HashMap.java:845) *** at java.util.HashSet $ HashIterator.next(HashSet.java:###)*** at sample .learning.SetIterationExample.main(ListGetterIteration.java:25) 或者可能是HashMap异常应该被追踪为异常原因pof(我们的异常getCause()返回null),而不是例外? 我建议采取行少数盐(特别是在failfast /尽力而为的行为例外) – 2013-02-25 10:22:35

+0

Set上的迭代器的名称无关紧要,只要它与问题集 – 2013-02-25 10:24:39

+2

@SatyanRaina这将需要一个额外的包装类被写入,并会无缘无故地引入另一层方法调用。支持映射的'keySet()。iterator()'服从'HashSet'内容的迭代器的所有条件,所以使用它是非常合理的。当您读取堆栈跟踪并找出_your_代码首先调用到'java.util'中时,您会立即看到正在处理的迭代器。 – 2013-02-25 13:12:46

相关问题