談一談ConcurrentModificationException


本文原創地址,我的博客https://jsbintask.cn/2019/04/09/jdk/jdk8-concurrentmodificationexception/(食用效果最佳),轉載請註明出處!

前言

ConCurrentModificationException是jdk用於限制併發情況下容器結構改變的異常類。當一個線程操作一個容器時,此時如果有另一個線程修改了容器大小,將拋出這個異常,我們看下面兩段代碼



Code 2::

說明:一個線程進行list的排序操作,一個線程移除list中的元素,結果:

上面代碼說明不管是單線程情況下還是多線程併發運行模式下,一旦在某些情況下(如上面的遍歷,排序),容器的結構一旦被修改就將拋出ConCurrentModificationException

源碼解析

爲什麼會這樣呢,這樣是不是就代表這些容器是線程安全的呢? 我們通過源碼來討論一下。
首先第一個例子,一個線程進行遍歷操作:for(T t: Collections),通過查看字節碼知道,它其實就是使用了Iterator進行了遍歷操作:


接着查看ArrayList中的Iterator發現它內部是這麼定義的:

ArrayList內部有一個modCount成員變量,每次就行修改操作如增加,刪除等會增加該值:

而當初始化一個Iterator時,會記錄當前的modCount,以後每次操作(next(), remove())都會檢查該值:

一旦和記錄的初始值不相等,則會拋出異常!
同理,上面的排序操作sort()方法同樣是這麼定義的:

這樣我們上面的疑問就解開了,之所以會拋出異常,是因爲容器內部維護了一個變量modCount,在進行某些操作時(iterator,sort)時,會記錄當時的這個值,在操作過程中這個值一旦發生改變則會拋出ConcurrentModificationException。

jdk中,這種行爲被稱爲快速失敗,它的目的是爲了盡最大努力的檢測線程安全!但是! 它並不能保證容器的線程安全


這個例子中,我們使用多線程添加了10000個元素,最後成功添加的卻只有9993個元素,說明它內部並沒有保證線程安全! 當我們在併發情況下使用這些容器時就需要考慮線程安全問題,替換線程安全的容器類(如ConcurrentHashMap, Vector, CopyOnWriteArrayList等)或者使用額外的同步手段如加鎖!

擴展

在單線程遍歷時,如果想刪除某個元素,可以使用iterator.remove()

ArrayList<String> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    list.add("list->" + (i + 1));
}

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String next = iterator.next();
    if (next.equals("list->3")) {
        iterator.remove();
    }

    System.out.println(next);
}
System.out.println(list);


對於ArrayList而言,你也可以調用lsitIterator()方法獲取內部的ListIterator從而進行添加,插入操作:

ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            list.add("list->" + (i + 1));
        }

        ListIterator<String> iterator = list.listIterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (next.equals("list->3")) {
                iterator.remove();

            }

            System.out.println(next);
            iterator.add("list->7");
        }
        System.out.println(list);


關注我,這裏只有乾貨!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章