併發修改異常 ConcurrentModificationException詳解
-
異常產生原因:併發修改異常指的是在併發環境下,當方法檢測到物件的併發修改,但不允許這種修改時,丟擲該異常。
-
異常丟擲在ArrayList類中的checkForComodification()方法中。
-
checkForComodification()方法實際上就是當modCount 變數值不等於expectedModCount變數值時,就會觸發此異常。
-
modCount :AbstractList類中的一個成員變數,由於ArrayList繼承自AbstractList,所以ArrayList中的modCount變數也繼承過來了。
-
expectedModCount:是ArrayList中內部類Itr的一個成員變數,當我們呼叫iterater()獲取迭代器方法時,會建立內部類Itr的物件,並給其成員變數expectedModCount賦值為ArrayList物件成員變數的值modCount【預期修改次數】。
-
檢視ArrayList的原始碼可知,modCount 初始值為0, 每當集合中新增一個元素或者刪除一個元素時,modCount變數的值都會加一,表示集合中結構修改次數多了一次
解決方案
當用迭代器遍歷元素時,集合不能修改,但是迭代器可以修改
由上圖可知,modCount和expectedModCount會一直相等,所以不會丟擲異常
舉例:使用List集合儲存字串元素,使用迭代器遍歷,遍歷的時候,如果遇到"java",就向集合中新增一個元素"shujia"
import java.util.ArrayList;
import java.util.ListIterator;
public class ListDemo1 {
public static void main(String[] args) {
ArrayList l2 = new ArrayList();
l2.add("hello");
l2.add("java");
l2.add("world");
l2.add("hello");
System.out.println(l2);
System.out.println("===============");
ListIterator listIterator = l2.listIterator();
while (listIterator.hasNext()){
Object o = listIterator.next();
String s = (String) o; //下轉型。因為Object類沒有equals()方法
if (s.equals("java")){
listIterator.add("shujia"); //List迭代器追加
}
}
System.out.println(l2);
}
}
擴充:當要刪除的元素在集合中的倒數第二個元素的時候,刪除元素不會產生併發修改異常。
原因:因為在呼叫hasNext()方法的時候,cursor = size是相等的,hasNext()方法會返回false, 所以不會執行next()方法,也就不會呼叫checkForComodification()方法,就不會發生併發修改異常。
小結論:
- 迭代器呼叫remove()方法刪除元素,底層還是呼叫的集合的刪除元素的方法;
- 在呼叫remove()方法後,都會將modCount的值賦值給expectedModCount,保證了它兩的值永遠都是相等的,所以也就不會產生併發修改異常;