在JDK1.6中的HashSet.java中,有一些关于HashSet迭代器的fail-fast属性的评论。
此类迭代器方法返回的迭代器是故障快速的:如果在迭代器创建后的任何时候,以除迭代器自己的remove方法之外的任何方式修改集合,则迭代器将抛出ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是冒着在未来不确定的时间出现任意、不确定行为的风险。
我能理解上面的一段,因为它非常简单明了,但我不能理解下面的一段。如果我有一些简单的例子来说明故障快速迭代器甚至可能失败,我可能会理解。
请注意,迭代器的故障快速行为无法得到保证,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。故障快速迭代器在尽力而为的基础上抛出ConcurrentModificationException。因此,编写一个依赖于此异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测错误。
EDIT:很抱歉我使用了一个列表,但这是相同的想法。这是关于迭代器的,而不是它背后的Collection
编辑2:同样,这种情况在多线程环境中发生的可能性要大得多,在这种环境中,你有两个线程,一个读取,一个写入。当您进行编码时,很难看到这些。要解决这些问题,您需要在列表上实现读/写锁以避免这种情况。
以下是注释的代码示例:
Iterator itr = myList.iterator();
while(itr.hasNext())
{
Object o = itr.next();
if(o meets some condition)
{
//YOURE MODIFYING THE LIST
myList.remove(o);
}
}
规范所说的是,你不能依赖这样的代码:
while(itr.hasNext())
{
Object o = itr.next();
try
{
if(o meets some condition)
myList.remove(o);
}
catch(ConcurrentModificationException e)
{
//Whoops I abused my iterator. Do something else.
}
}
相反,您可能应该将内容添加到新列表中,然后将myList引用切换到刚刚创建的引用。这能解释情况吗?
第二段背后的想法是防止您编写这样的代码:
boolean ok = false;
do {
try {
doTheModification();
ok = true;
} catch {
// Consurrent modification - retry
}
} while (!ok);
虽然这不是一个好的代码,但注释指出该代码是无效的(与次优相反)。他们说,异常可能根本不会发生,所以上面的循环可能会无声地产生故障。