2

在 JDK 1.6 的 HashSet.java 中,有一些关于 HashSet 迭代器的 fail-fast 属性的注释。

此类的迭代器方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间修改集合,除了通过迭代器自己的 remove 方法之外,迭代器会抛出 ConcurrentModificationException。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

我可以理解上面的段落,因为它非常简单明了,但我无法理解下面的段落。如果我有一些简单的例子表明快速失败的迭代器甚至会失败,我可能会理解它。

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

4

2 回答 2

2

编辑:对不起,我使用了一个列表,但这是相同的想法。这是关于迭代器,而不是它背后的集合。

EDIT2:这也更有可能发生在多线程环境中,你有两个线程,一个阅读,一个写作。当您编码时,这些更难看到。要解决这些问题,您需要在列表上实施读/写锁以避免这种情况。

这是注释的代码示例:

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 引用切换到刚刚创建的引用。这能说明情况吗?

于 2012-08-27T16:10:14.127 回答
2

第二段背后的想法是防止您编写这样的代码:

boolean ok = false;
do {
    try {
        doTheModification();
        ok = true;
    } catch {
        // Consurrent modification - retry
    }
} while (!ok);

虽然这不是一个好的代码,但注释指出此代码无效(与次优相反)。他们说异常可能根本不会发生,所以上面的循环可能会默默地产生失败。

于 2012-08-27T16:11:45.933 回答