Java には、フェイルセーフとフェイルファストの 2 種類の反復子があります。
これは何を意味し、それらの違いは何ですか?
それらの違いは何ですか...
「フェイルセーフ」(エンジニアリングでは) は、何かが失敗して損傷がまったく発生しないか、最小限に抑えられることを意味します。厳密に言えば、Java にはフェイルセーフ イテレータのようなものはありません。イテレータが失敗した場合 (通常の「失敗」の意味で)、損傷が発生することが予想されます。
あなたは実際には「弱い一貫性のある」イテレータを意味していると思います。javadoc は次のように述べています。
「ほとんどの並行コレクション実装 (ほとんどのキューを含む) は、通常の java.util 規則とは異なります。そのイテレーターとスプリッテレーターは、ファスト フェイル トラバーサルではなく弱い一貫性を提供します。」
通常、弱い整合性とは、反復と同時にコレクションが変更された場合、反復が参照する内容の保証が弱くなることを意味します。(詳細は、各同時収集クラスの javadoc で指定されます。)
「フェイルファスト」(システム設計における) とは、障害状態が (可能な場合は1 ) 損傷が大きくなりすぎる前に検出されるように、障害状態が積極的にチェックされることを意味します。Java では、フェイルファスト イテレータは をスローして失敗しますConcurrentModificationException
。
「フェイルファスト」と「弱い一貫性」の代替は、反復が予期せず失敗するセマンティックです。たとえば、間違った答えを返したり、予期しない例外をスローしたりすることがあります。Enumeration
(これは、初期バージョンの Java における APIの一部の標準実装の動作でした。)
...そして、それらはコレクションに使用するイテレータとは異なります。
いいえ。これらは、標準の Collection 型によって実装される反復子のプロパティです。つまり、同期と Java メモリ モデルに関して正しく使用された場合、"フェイル ファスト" または "弱い一貫性" のいずれかになります1。
通常、フェイルファスト反復子はvolatile
、コレクション オブジェクトのカウンターを使用して実装されます。
Iterator
と、カウンタの現在の値がIterator
オブジェクトに埋め込まれます。Iterator
と、メソッドは 2 つのカウンター値を比較し、異なる場合は CME をスローします。対照的に、一貫性の低いイテレータは通常、軽量であり、各並行コレクションの内部データ構造のプロパティを活用します。一般的なパターンはありません。興味がある場合は、さまざまなコレクション クラスのソース コードを読んでください。
1 - フェイルファスト イテレータの動作は、アプリケーションが同期とメモリ モデルに関して正しく実装されていることを前提としています。(つまり、アプリケーションはスレッドセーフです。) たとえば、ArrayList
適切な同期を行わずに を繰り返した場合、「高速失敗」メカニズムは同時変更を検出する必要がありますが (保証されていません)、リストを防止することはできません。アプリケーションの安全でない動作による破損を防ぎます。説明のために、javadocにVector.iterator()
は次のように記載されています。
「イテレータのフェイルファスト動作は、一般的に言えば、同期されていない同時変更が存在する場合にハードな保証を行うことは不可能であるため、保証できません。フェイルファストイテレータ
ConcurrentModificationException
はベストエフォートベースでスローします。したがって、正確性をこの例外に依存するプログラムを作成するのは間違っています。イテレータのフェイルファスト動作は、バグを検出するためだけに使用する必要があります。」
それらはどちらかといえばフェイルファストで一貫性の低いタイプです。
反復中にコレクションのメソッド (追加/削除) によってコレクションが変更された場合、java.util
パッケージの反復子がスローされます。ConcurrentModificationException
通常、パッケージの反復子java.util.concurrent
はスナップショットを反復処理し、同時変更を許可しますが、反復子の作成後にコレクションの更新が反映されない場合があります。