java.util.ConcurrentModificationException at java.util.ArrayList$ArrayListIterator.next(ArrayList.

3809 ワード

java.util.ConcurrentModificationException at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)の解決
プロジェクトでこのバグに遭遇しました.
java.util.ConcurrentModificationException at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573) at com.wanyue.tool.CleanActivity.clean(CleanActivity.java:149)
この例外について説明します.
An ConcurrentModificationException is thrown when a Collection is modified and an existing iterator on the Collection is used to modify the Collection as well.  

ConcurrentModificationExceptionが投げた条件は、反復集合時に反復器が集合を変更したことです.
一般的な栗を挙げると、例えばArraylistを反復するときにArraylistを削除するとその異常が放出されます
解析原因:集合中list setなどは同期を実現せず,マルチスレッドで集合を操作する際の同期操作は外部で制御する
Iteratorの仕組みを見てみましょう
An iterator over a sequence of objects, such as a collection.

If a collection has been changed since the iterator was created, methods next and hasNext() may throw a ConcurrentModificationException. It is not possible to guarantee that this mechanism works in all cases of unsynchronized concurrent modification. It should only be used for debugging purposes. Iterators with this behavior are called fail-fast iterators.

Implementing Iterable and returning an Iterator allows your class to be used as a collection with the enhanced for loop.

翻訳は、集合が自己作成反復器を変更した場合、nextメソッドとhasNextメソッド()は、ConcurrentModificationExceptionを放出する可能性があります.これは、このメカニズムの作業中に同期せずに同時に変更されるすべての状況を保証するために不可能です.デバッグの目的でのみ使用されるべきです.反復器とこの動作は、高速で失敗した反復器と呼ばれます.
Iteratorの動作原理に従って、独立したスレッドで完了し、Iteratorが実行するときに反復するオブジェクトは、可変の一方向の順序でなければなりません.
実際のソリューションを見てみましょう.
1)反復が必要なときにロックを1つ追加するが効率に影響する
2)前反復ごとにコレクションをコピーする
Arraylistにはtoarray()の方法があります
    /**
     * Returns a new array containing all elements contained in this
     * {@code ArrayList}.
     *
     * @return an array of the elements from this {@code ArrayList}
     */
    @Override public Object[] toArray() {
        int s = size;
        Object[] result = new Object[s];
        System.arraycopy(array, 0, result, 0, s);
        return result;
    }

toArray()メソッドはSystemを呼び出します.arraycopy(array, 0, result, 0, s); コレクションをコピー
マルチスレッドでArraylistを反復する必要がある場合、集合の後ろにtoArray()を追加して集合をコピーします.これにより、元のコレクションの変更操作はcopy後の新しいコレクションに影響しません.
反復時に元の集合に対してxxを呼び出す.toArray();方法でいいです.ここに記録しておきます.交流を歓迎します.