天天看點

疊代器并發修改異常ConcurrentModificationException

我們知道,使用疊代器周遊集合時,如果進行增删等操作,會抛出一個異常:ConcurrentModificationException并發修改異常,那麼為什麼會這樣呢?一起來研究研究

疊代器并發修改異常ConcurrentModificationException

如下,疊代時對集合coll進行删除操作,異常抛出

Iterator<Integer> it = coll.iterator();

        while (it.hasNext()) {
            int s = it.next();
            coll.remove(s);//執行該操作上面的next()會抛出ConcurrentModificationException并發修改異常
            System.out.println(s);
        }
           

我們尋找控制台的資訊進入java.util.ArrayList$Itr.next(ArrayList.java:893)

疊代器并發修改異常ConcurrentModificationException

發現在next方法中,有一個checkForComodification();方法,我們點進去檢視裡面都做了些什麼。

疊代器并發修改異常ConcurrentModificationException

是不是很熟悉,在if判斷中抛出了這個并發修改異常,那你可能會好奇了,這個modCount和expectedModCount又是什麼東西呢?

字面意思我們先大概了解一下,mod,是modification的簡寫,修改的意思,expected:期望的,這時我們可能就會想到:噢,修改值和期望值

也就是說在疊代時,調用next方法,會調用checkForComodificatio()進行判斷,如果修改值和期望值不一緻,就抛出并發修改的異常。

我們繼續Ctrl點modCount找到它的位置,發現在AbstractList中628行定義它,初始化為0

疊代器并發修改異常ConcurrentModificationException
疊代器并發修改異常ConcurrentModificationException

再看expectedModCount,建立時會把modCount的值指派給它

疊代器并發修改異常ConcurrentModificationException

而這兩個變量,modCount是在集合中,expectedModCount在接口中,換句話說:建立集合時會定義變量modCount,預設為0,建立疊代器時将定義expectedModCount并将modCount目前的值指派給它

我們繼續往下看,诶?

疊代器并發修改異常ConcurrentModificationException

當我們調用集合的add方法時,modCount會自增,同理,調用remove方法時,也會自增(其他一些方法同理)

疊代器并發修改異常ConcurrentModificationException

到這裡,我們舉一個簡單的例子來說明一下整個流程:

1.現在我建立一個ArrayList list,此時modCount為0,然後我進行4次添加操作,list.add(1),此時modCount的值為4

2.然後我建立疊代器,Iterator it = list.iterator();

此時會将modCount的值指派給expectedModCount****,expectedModCount現在也為4

3.緊接着我使用while循環來開始周遊list

while (it.hasNext()) {

int s = it.next();

list.remove(s);

System.out.println(s);

}

4.周遊時抛出了異常,這裡調用remove(s)時,modCount++,由4變成了5,上面我們講過,next方法中會調用checkForComodificatio方法判斷modCount和expectedModCount的值是否相等,不相等就會抛出異常,此時modCount為5,expectedModCount為4,下次循環到next方法,異常就抛出了

那該如何解決呢?我們直接上答案,使用ListIterator lit = list.listIterator();建立疊代器,用lit的add或remove來進行增删,你可能會想wtf?為毛這個就可行了!

别急,我們再一起到源碼中找答案

疊代器并發修改異常ConcurrentModificationException
疊代器并發修改異常ConcurrentModificationException

是不是瞬間就明白了,這裡的add方法中加上了一個同步操作,讓modCount和expectedModCount始終保持一緻,所有就不會抛出該異常了。

over

樓主是一隻萌新,如有錯誤之處還望大家指正