我正在迭代Hashtable
并且在某一时刻,我向Hashtable
添加了一些内容,这显然给了我ConcurrentModificationException
。我理解为什么我会收到错误,但有没有办法解决这个问题,以至于我仍然可以遍历Hashtable
并同时添加值?
答案 0 :(得分:7)
来自文档
迭代器返回的迭代器 返回的集合的方法 所有这个类的“集合视图 方法“快速失败:如果 Hashtable在结构上进行了修改 在迭代器之后的任何时间 以任何方式创造,除了通过 迭代器自己的删除方法, 迭代器会抛出一个 ConcurrentModificationException的。从而, 面对并发 修改,迭代器失败 快速而干净,而不是 冒着任意,不确定的风险 在一个不确定的时间的行为 未来。枚举返回 通过Hashtable的键和元素 方法不是快速失败。
注意一个快速失败的行为 迭代器无法保证 一般来说,是不可能的 做出任何艰难的保证 存在未同步的并发 修改。失败快速的迭代器 抛出ConcurrentModificationException 尽力而为。因此,它 写一个程序是不对的 依赖于这个例外 正确性:失败的快速行为 迭代器应该只用于 检测错误。
如果您需要这种行为,您可以安全地复制该组密钥并遍历该副本。如果散列表很大并且复制键集可能很昂贵,那么另一个选择是在迭代期间添加到单独的集合并添加迭代后单独集合的元素。
答案 1 :(得分:2)
您可能还想了解CopyOnWriteSet,它专门为安全迭代而设计,同时修改了set。请注意,迭代器只能看到原始集。在下一次迭代之前,任何添加都不可见。
http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CopyOnWriteArraySet.html
这在许多读者/少数作家场景中最有用。如果在同一代码路径中进行读写,则不太可能是最有效的解决方案。
答案 2 :(得分:1)
创建一个新的Hashtable,您可以添加新条目;然后当你完成迭代时,添加第一个表中的条目。
或者,如果需要,您可以跳过原始表中存在的密钥。
答案 3 :(得分:0)
另一种选择是使用ConcurrentHashMap而不是HashMap。但是:
ConcurrentHashMap的迭代器被定义为在迭代器创建时或之后的某个时间返回反映状态的对象。关于行为的更精确的陈述是在相关方法的javadoc中。
ConcurrentHashMap可能比常规HashMap慢。