java ConcerentModificationException探究

5944 ワード

集合構造が修正されると、Concerent Modification Exceptionをスローします。fail-fastは以下の2つの状況の下でConcerentModification Exceptionを投げ出します。
(1)単一スレッド環境セットを作成し、それを巡回する過程で構造を修正した。  
remove()の方法はexpectModcountとmodcountを同じにするので、この異常は投げられません。
(2)マルチスレッド環境は、スレッドがこのセットを巡回している間、他のスレッドがこのセットの構造を修正した。
以下のとおりです
private static void test0() {

        List<String> list = new ArrayList<>();
        list.add("a1");
        list.add("a2");
        list.add("a3");
        list.add("a4");
        list.add("a5");
        list.add("a6");
        list.add("a7");
        list.add("a8");

        for (String s : list) {
            list.remove(s);
        }

        System.out.println(list);

    }
 
運転中に異常が発生します。
java.util.C.oncurrent ModificationException
もし、巡回中に削除操作をしたいなら?リブテラーを借りると、次のようになります。
private static void test1() {

        List<String> list = new ArrayList<>();
        list.add("a1");
        list.add("a2");
        list.add("a3");
        list.add("a4");
        list.add("a5");
        list.add("a6");
        list.add("a7");
        list.add("a8");

        Iterator<String> iter = list.iterator();
        while (iter.hasNext()) {
            String str = iter.next();
            System.out.println(str);

            //iter.remove();
            if (Randoms.random(1, 9) % 2 == 0) {
                iter.remove();
            }
        }

        System.out.println(list);

    }
 
ここではlist.removeを使っていません。iter.reomveですが、実際のlistの中の要素はもう削除されました。そして投げられた異常はありません。なぜですか?
デバッグの時、私達はiter.reomveが最終的に呼び出されたのを発見しました。
public E remove(int index)
だから自然はもとの集合に影響しました。
Iteratorは作成された後、元のオブジェクトに向けたシングルチェーンインデックス表を作成します。リスト削除要素の中でインデックスに影響がない場合、Iterator.remove()メソッドは現在の反復オブジェクトを削除しながらインデックスの整合性を維持します。
私たちはセグメントコードを見ます。
 
private static void test2() {
 List list2 = Arrays.asList(new String[]{"a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8",});

Iterator iter2 = list2.iterator(); 

while (iter2.hasNext()) { 
      String str = iter2.next(); System.out.println(str);

        //iter.remove();
        if (Randoms.random(1, 9) % 2 == 0) {
            iter2.remove();
        }
    }

    System.out.println(list2);
}
 
結果:
例外java.lang.Unisported Operation Exceptionを投げることができます。
なぜですか?test 1と同じ感じですか?
ソースコードのAraysを確認します。
public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable{...}
 
二つのArayListは同じクラスではないのに同じ名前を付けていることが分かりました。
java.util.Arays.ArayList!=java.util.ArayList
あなたはまだあなたと同じ名前ですが、別の彼です。
java.util.Arays.ArayListはremove方法を実現していませんので、UnipportedOperation Exceptionを投げ出しました。
簡単そうな問題はもう少し考えればいいです。