2

JDK 1.6 の HashSet.java には、HashSet の反復子のフェイルファスト プロパティに関するコメントがいくつかあります。

このクラスの iterator メソッドによって返される反復子はフェイルファストです。反復子の作成後に、反復子自体の remove メソッド以外の方法でセットが変更されると、Iterator は ConcurrentModificationException をスローします。したがって、同時変更に直面した場合、反復子は、将来の不確定な時点で恣意的で非決定論的な動作を危険にさらすのではなく、迅速かつ明確に失敗します。

上の段落はかなり単純明快なので理解できますが、次の段落は理解できません。フェイルファスト イテレータが失敗する可能性があることを示す簡単な例があれば、それを理解できるかもしれません。

イテレータのフェイルファスト動作は保証できないことに注意してください。一般的に言えば、同期されていない同時変更が存在する場合にハードな保証を行うことは不可能であるためです。フェイルファスト イテレーターは、ベスト エフォート ベースで ConcurrentModificationException をスローします。したがって、その正確性をこの例外に依存するプログラムを作成するのは誤りです。反復子のフェイルファスト動作は、バグを検出するためだけに使用する必要があります。

4

2 に答える 2

2

2 番目の段落の背後にある考え方は、次のようなコードを記述できないようにすることです。

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

これは最初から適切なコードではありませんが、コメントでは、このコードは無効であると述べられています (最適ではないなどとは対照的に)。彼らは、例外がまったく続かない可能性があると言っているので、上記のループはサイレントに失敗する可能性があります。

于 2012-08-27T16:11:45.933 に答える
2

編集:リストを使用して申し訳ありませんが、同じ考えです。これはイテレータに関するものであり、その背後にあるコレクションではありません。

EDIT2:また、これはマルチスレッド環境で発生する可能性がはるかに高く、2つのスレッド、1つの読み取り、1つの書き込みがあります。これらは、コーディングしているときに見るのが難しくなります。これらを修正するには、これを回避するためにリストに読み取り/書き込みロックを実装する必要があります。

コメントのコード例を次に示します。

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 に答える