併發修改異常 ConcurrentModificationException詳解

hello_future發表於2024-08-11

併發修改異常 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()方法,就不會發生併發修改異常。

小結論:

  1. 迭代器呼叫remove()方法刪除元素,底層還是呼叫的集合的刪除元素的方法;
  2. 在呼叫remove()方法後,都會將modCount的值賦值給expectedModCount,保證了它兩的值永遠都是相等的,所以也就不會產生併發修改異常;

相關文章