选自《阿里巴巴JAVA开发手册》
图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?
大家讲道理2017-04-18 10:56:42
エラーの原因は、報告されたエラー checkForComodification()
から知ることができます。エラーを回避したい場合は、 modCount != ExpectedModCount
を として保持する必要があります。 false
。 list.remove(Object)
は fastRemove(int)
メソッドを呼び出します。このとき、必ず modCount
が変更されます。今度はエラーが発生します。 Iterator<String> iterator = list.iterator()
;このメソッドの実装は、内部クラス Itr
を返します (このクラスは反復で使用されます)。 process ) ですが、この iterator.remove()
ではエラーが発生しないのはなぜでしょうか。その理由は、このメソッドの実装が実際の ArrayList.this.remove
より前に実行されるためです。 checkForComodfication
はチェックして remove
を実行し、expectedModCount = modCount
にするため、エラーは発生しません。 checkForComodification()
,如果要避免错误需要保持 modCount != expectedModCount
为 false
。list.remove(Object)
会去调用fastRemove(int)
方法,这个时候必然会去修改 modCount
,这个时候就会出现错误。Iterator<String> iterator = list.iterator()
;这个方法的实现就是返回一个内部类 Itr
,(迭代的过程都是使用的这个类),但是为什么这个 iterator.remove()
不会出现错误了,原因在与这个方法的实现是在进行实际的 ArrayList.this.remove
之前进行的 checkForComodfication
检查,remove
之后又使 expectedModCount = modCount
,所以不会出现错误。
Itr.remove
Itr.remove
実装リーリー
何か間違っていたらご指摘ください @ChaCha哥 @puluyinyi🎜PHP中文网2017-04-18 10:56:42
シングルスレッドの場合、List を走査するときに要素を削除するときは、List の Remove メソッドではなく Iterator の Remove メソッドを使用する必要があります。そうしないと、ConcurrentModificationException が発生します。想像してみてください。教師がクラス全体の生徒の数を数えているときに、生徒がルールを守らずに出たり入ったりした場合、教師は間違いなく生徒の数を数えることはできません。
マルチスレッドの場合は、私のブログの 1 つを参照してください: http://xxgblog.com/2016/04/02...
天蓬老师2017-04-18 10:56:42
まず第一に、これにはマルチスレッド操作が含まれます。Iterator はマルチスレッド操作をサポートしていません。List クラスは、変更の数を記録するために内部で modCount 変数を維持します
例: ArrayList ソース コード
イテレーターが生成されるたびに、イテレーターは next() メソッドが呼び出されるたびに modCount を記録します。レコードは外部クラス List の modCount と比較され、一致しないことが判明した場合は、マルチスレッド編集例外がスローされます。
なぜこんなことをするのですか?私の理解では、走査されるコレクションのコンテンツと密接に結合されたイテレータを作成したということです。つまり、このイテレータに対応するコレクションのコンテンツが現在のコンテンツであることを意味します。バブルソートのとき、まだデータをコレクションに挿入しているスレッドがありますよね?したがって、Java はこの単純な処理メカニズムを使用して、トラバーサル中にコレクションが変更されるのを防ぎます。
なぜ「1」を削除するだけで済むのかというと、その理由はforeachのhasNext()メソッドとイテレータにあります。実はforeachの糖衣構文は
です。 リーリーしたがって、すべてのループは最初に hasNext() を実行します。そのため、ArrayList の hasNext() がどのように書かれているかを見てください:
リーリーcursor はイテレータの位置をマークするために使用される変数です。この変数は 0 から始まり、next が呼び出されるたびに +1 演算を実行します。つまり、次のようになります。
コードで「1」、size=1、cursor を削除した後。 =1、この hasNext() が false を返すと、ループが終了するため、反復子は 2 番目の要素を見つけるために next を呼び出さないため、modCount を検出する方法がなく、マルチスレッド変更例外は発生しません
しかし、 "2" を削除すると、反復子は next を 2 回呼び出し、size=1、cursor=2、および hasNext() が true を返したので、反復子は愚かにも next() を再度呼び出し、これにより modCount が等しくなくなり、スローされました。マルチスレッド変更の例外。
セットに要素が 3 つある場合、「1」を削除すると例外がスローされることがわかりますが、「2」を削除しても問題ありません。その理由は、上記のプログラムの実行順序が一貫しているためです。
黄舟2017-04-18 10:56:42
要素を追加または削除するとコレクション内の番号が変わるため、たとえば、コレクションに 10 個の要素がある場合、要素を追加するとき、または要素を削除するときに、その番号を 10 回走査する必要があります。トラバーサルの回数が正しくないため、エラーが報告されます
伊谢尔伦2017-04-18 10:56:42
文書内の黄色の説明は非常に興味深いです。
この例の実行結果は誰もが予想を超えるものになるでしょう。それでは、「1」を「2」に置き換えてみてください。同じ結果になりますか?
まだ ArrayList
のソースコードを見る必要がありますが、一目でそれがわかります。
PHP中文网2017-04-18 10:56:42
ArrayList はスレッドセーフではありません。つまり、トラバース中に List を変更することになります。この場合、ArrayList は同時変更例外をスローします。