Javaのフェイルセーフおよびフェイルファストイテレータとは


101

Javaのイテレータには、フェイルセーフとフェイルファストの2つのタイプがあります。

これはどういう意味ですか、それらの違いは何ですか?



2
Java SE仕様では、「フェイルセーフ」という用語をイテレータの説明に使用していないことに注意してください。したがって、この用語は避けることをお勧めします。参照してくださいstackoverflow.com/a/38341921/1441122
スチュアート・マークス

回答:


84

それらの違いは何ですか...

「フェイルセーフ」とは(エンジニアリングにおいて)、損傷がまったくないか最小限の方法で何かが故障したことを意味します。厳密に言えば、Javaにはフェイルセーフイテレータのようなものはありません。イテレーターが失敗した場合(通常の「失敗」の意味)、損傷が発生することが予想されます。

あなたが実際に「弱一貫性」のイテレータを意味しているのではないかと思います。javadocは言う:

「ほとんどの並行コレクション実装(ほとんどのキューを含む)も、通常のjava.utilの規則とは異なります。それらのイテレーターとスプリッターは、高速失敗トラバーサルではなく、弱整合性を提供します。」

通常、弱い整合性とは、コレクションが反復と同時に変更された場合、反復で表示されるものの保証が弱いことを意味します。(詳細は、各並行コレクションクラスjavadocsで指定されます。)

「フェイルファスト」(システム設計で)は、故障状態を積極的にチェックして、(可能な場合は1)過度の損傷を与える前に故障状態を検出することを意味します。Javaでは、Fail-Fastイテレータはをスローすることで失敗しますConcurrentModificationException

「フェイルファスト」および「弱一貫性」の代替手段は、反復が予期せず失敗するセマンティックです。たとえば、時々間違った答えを出したり、予期しない例外をスローしたりします。(これは、EnumerationJavaの初期バージョンでのAPIの一部の標準実装の動作でした。)

...そして、それらはコレクションに使用するイテレータとは異なります。

いいえ。これらは、標準のコレクション型によって実装されるイテレータのプロパティです。つまり、同期とJavaメモリモデルに関して正しく使用すると、「フェイルファースト」または「弱整合性」になります1


フェイルファストイテレータは通常volatile、コレクションオブジェクトのカウンタを使用して実装されます。

  • コレクションが更新されると、カウンターが増加します。
  • ときにIterator作成され、カウンタの現在の値が中に埋め込まれているIteratorオブジェクト。
  • ときにIterator操作が行われ、方法は、2つのカウンタ値を比較し、両者が異なる場合CMEをスロー。

対照的に、弱整合性のイテレータは通常、軽量であり、各並行コレクションの内部データ構造のプロパティを活用します。一般的なパターンはありません。興味があれば、さまざまなコレクションクラスのソースコードを読んでください。


1-ライダーは、フェイルファストの動作が、同期とメモリモデルに関してアプリケーションIDを正しく想定していることを示しています。つまり、(たとえば)ArrayListを適切に同期せずに反復すると、リストの結果が破損する可能性があります。「ファストフェイル」メカニズムはおそらく同時変更を検出しますが(これは保証されていません)、根本的な破損は検出しません。例として、Javadoc for Vector.iterator()は次のように言っています。

「イテレータのフェイルファスト動作は、非同期の同時変更が存在する場合、一般的には難しい保証ができないため保証できません。フェイルファストイテレータConcurrentModificationExceptionはベストエフォートベースでスローします。したがって、この例外に正確性を依存するプログラムを書くのは間違っています。イテレータのフェイルファスト動作は、バグを検出するためだけに使用する必要があります。」


多分少し無関係ですが、この質問を補足するかもしれません。たとえば、CoWで使用されるスナップショットスタイルはどうですか?より具体的には、CoWイテレーターが「決して」繰り返し処理する基になる配列(またはスナップショット)が、変更を呼び出すことができるため、他のスレッドによって加えられた変更がどのように見えるかがわかりませんsetArray
標準出力

一貫性の弱いイテレータの実装について話すことは、このQ&Aの範囲を超えると判断しました。
スティーブンC

42

それらはむしろフェイルファスト弱く一貫したタイプです:

反復中にコレクションのメソッド(追加/削除)によってコレクションが変更された場合、java.utilパッケージのイテレータがスローConcurrentModificationExceptionします

java.util.concurrentパッケージのイテレータは通常、スナップショットを反復処理し、同時変更を許可しますが、イテレータの作成後のコレクションの更新を反映しない場合があります。


イテレータは、列挙がフェイルセーフである一方でフェイルファストの例です
Ajay Sharma

5
@AjaySharma-2つの点で正しくありません。1)どちらでもない、IteratorまたはEnumeration動作をフェイルファストまたはフェイルセーフとして指定しない。これは、特定の実装(すなわち、特定のコレクションですiterator()/ elements()動作を指定するなど、これらのオブジェクトを返すメソッド)。2)典型的な列挙の実装は、フェイルファストでもフェイルセーフでもありません
スティーブンC

22

唯一の違いは、フェイルセーフイテレータは、フェイルファストイテレータとは異なり、例外をスローしません。

1つのスレッドがコレクションを反復処理している間にコレクションが構造的に変更された場合。これは、元のコレクションではなくコレクションのクローンで作業するためであり、フェイルセーフイテレータと呼ばれるのはそのためです。

CopyOnWriteArrayListのイテレーターは、フェイルセーフイテレーターの例です。また、ConcurrentHashMapによって作成されたイテレーターkeySetもフェイルセーフイテレーターであり、JavaでConcurrentModificationExceptionをスローすることはありません。


ConcurrentHashMapイテレータがclone()で動作していないのがわかりません.. :(反復中に更新の一部が反映されることがあります..
Kanagavelu Sugumar 2013年

0

このシナリオは「並行処理」に関連しており、同じリソースにアクセスする複数のユーザーを意味します。このような状況では、ユーザーの1人がそのリソースを変更しようとすると、 'ConcurrentProcessingException'が発生します。その場合、他のユーザーが不適切なデータを取得するためです。このタイプはどちらも、このような状況に関連しています。

簡単に言えば、

フェイルファースト:

  • 構造の変更(追加、更新、削除)が発生した場合、イテレータはすぐにConcurrentModificationExceptionをスローします。
  • 例:ArrayList、HashMap、TreeSet

フェイルセーフ :

  • イテレータは、元のイテレータではなく、コレクションのクローンを操作するため、例外をスローしません。つまり、それらはフェイルセーフのイテレータです。
  • 例:CopyOnWriteArrayList、ConcurrentHashMap
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.