フェイルセーフイテレータとフェイルファストイテレータ

フェイルセーフイテレータとフェイルファストイテレータ

1. 前書き

この記事では、Fail-FastおよびFail-SafeIteratorsの概念を紹介します。

Fail-Fastシステムは、可能な限り高速に操作を中止し、障害を即座に公開して、操作全体を停止します。

一方、Fail-Safe systems don’t abort an operation in the case of a failure. Such systems try to avoid raising failures as much as possible.

2. フェイルファストIterators

基になるコレクションが変更されると、Javaのフェイルファストイテレータは機能しません。

Collectionsは、modCountと呼ばれる内部カウンターを維持します。 アイテムがCollectionに追加または削除されるたびに、このカウンターはインクリメントされます。

反復するとき、各next()呼び出しで、modCountの現在の値が初期値と比較されます。 不一致がある場合は、ConcurrentModificationExceptionをスローして、操作全体を中止します。

ArrayListHashMapなどのjava.util packageからのCollectionsのデフォルトのイテレータ。 フェイルファストです。

ArrayList numbers = // ...

Iterator iterator = numbers.iterator();
while (iterator.hasNext()) {
    Integer number = iterator.next();
    numbers.add(50);
}

上記のコードスニペットでは、変更が実行された後の次の反復サイクルの開始時にConcurrentModificationExceptionがスローされます。

同時変更の場合の動作を予測することは不可能であるため、Fail-Fastの動作がすべてのシナリオで発生することが保証されているわけではありません。 These iterators throw ConcurrentModificationException on a best effort basis

Collectionでの反復中に、an item is removed using Iterator‘s remove() method, that’s entirely safe and doesn’t throw an exception

ただし、Collectionremove()メソッドを使用して要素を削除すると、例外がスローされます。

ArrayList numbers = // ...

Iterator iterator = numbers.iterator();
while (iterator.hasNext()) {
    if (iterator.next() == 30) {
        iterator.remove(); // ok!
    }
}

iterator = numbers.iterator();
while (iterator.hasNext()) {
    if (iterator.next() == 40) {
        numbers.remove(2); // exception
    }
}

3. フェイルセーフイテレータ

フェイルセーフイテレーターは、例外処理の不便さよりも失敗の欠如を好みます。

これらのイテレータは、実際のCollectionのクローンを作成し、それを反復処理します。 イテレータの作成後に変更が発生した場合、コピーはそのまま残ります。 したがって、これらのIteratorsは、変更された場合でもCollectionをループし続けます。

ただし、真にフェイルセーフなイテレータのようなものはないことを覚えておくことが重要です。 正しい用語は「弱一貫性」です。

つまり、if aCollection is modified while being iterated over, what the Iterator sees is weakly guaranteedです。 この動作はCollectionsごとに異なる可能性があり、そのような各CollectionのJavadocに記載されています。

ただし、フェイルセーフIteratorsにはいくつかの欠点があります。 欠点の1つは、実際のCollectionではなくクローンで機能するため、Iterator isn’t guaranteed to return updated data from the Collectionが機能することです。

もう1つの欠点は、時間とメモリの両方に関して、Collectionのコピーを作成するオーバーヘッドです。

ConcurrentHashMapCopyOnWriteArrayListなどのjava.util.concurrentパッケージのCollections上のIterators。 本質的にフェイルセーフです。

ConcurrentHashMap map = new ConcurrentHashMap<>();

map.put("First", 10);
map.put("Second", 20);
map.put("Third", 30);
map.put("Fourth", 40);

Iterator iterator = map.keySet().iterator();

while (iterator.hasNext()) {
    String key = iterator.next();
    map.put("Fifth", 50);
}

上記のコードスニペットでは、フェイルセーフIteratorを使用しています。 したがって、反復中に新しい要素がCollectionに追加されても、例外はスローされません。

デフォルトのイテレータ_ for the _ConcurrentHashMapは弱い一貫性があります。 これは、このIteratorが同時変更を許容でき、Iteratorが構築されたときに存在していた要素をトラバースし、構築後のCollectionへの変更を反映する可能性があることを意味します(ただし、保証されません)。 Iterator

したがって、上記のコードスニペットでは、反復は5回ループします。これは、it does detect the newly added element to the Collection.を意味します。

4. 結論

このチュートリアルでは、Fail-SafeおよびFail-FastIteratorsの意味と、これらがJavaでどのように実装されているかを確認しました。

この記事に示されている完全なコードは、over on GitHubで入手できます。