3

「標準例外の使用を優先する」である「効果的なJava」アイテム60を読んでいます。

知っておく価値のあるもう 1 つの汎用例外は、ConcurrentModificationException です。この例外は、単一のスレッドまたは外部同期で使用するように設計されたオブジェクトが同時に変更されていることを検出した場合にスローされる必要があります。

通常CME、ループ中にコレクションから削除しようとすると、人々は直面します。

しかし、ここで私は、自己実装されたクラスオブジェクトの同時変更を検出するための簡潔な例は何でしょうか?

別のスレッドが false であるフラグに直面した場合、内部オブジェクトと関連するブール値フラグを同期してから例外をスローするようなものになると思います。

ソースで見つけた簡単な調査のためにArrayList

 final void checkForComodification() {
     if (modCount != expectedModCount)
         throw new ConcurrentModificationException();
 }

しかし、方法の背後にある原則modCountは維持されています。デクリメントされている場所を見つけることができません。

4

3 に答える 3

3

変更カウントは、基本的にコレクションの状態の「リビジョン番号」です。コレクションの構造が変更されるたびに増分されます。減少することはありません。

反復を開始すると、反復子は mod カウントの値を記憶します。次に、コンテナの現在の mod カウントが記憶された値と等しいことを定期的にチェックします。そうでない場合、つまり反復が開始されてから構造的な変更があった場合は、 aConcurrentModificationExceptionがスローされます。

于 2013-03-29T13:00:48.447 に答える
2

この種の動作を自分で実装する方法については、オブジェクトへのアクセスが適切に同期されていない場合、クラスが正しく機能するためのいくつかの前提に依存する可能性があります。これらの仮定を確認し、それらが正しくないことがわかった場合は CME をスローしてください。

の例ではArrayList、反復中にリストの構造を変更する人ArrayListはいないと想定されているため、反復中に変更されないはずの変更カウントを追跡します。

ただし、このチェックは、不正なアクセスが奇妙な動作ではなくクリーンな例外を引き起こす可能性を高めるためだけに存在します。言い換えれば、この例外は開発者にとって単なる助けであり、正確さを強制する必要はありません。遭遇したら妥協。

クラスのパフォーマンスに大きな影響を与えないこの種のヘルプを提供することは良い考えですが、正しい使用を保証するために同期などを使用することはおそらく悪い考えです。

ArrayListこれが、の API ドキュメントに次のように記載されている理由です。

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

于 2013-03-29T13:21:24.160 に答える
0

したがって、一般的なアプローチは次のとおりです。オブジェクトの現在の状態を覚えておいて、オブジェクトにアクセスしようとするたびにその状態を確認し、状態が変化した場合は例外をスローしてください。

于 2013-03-29T13:21:28.573 に答える