Java異常之----Exception in thread“main” java util ConcurrentModificationException的解決方案

本文目錄

一、錯誤描述

二、錯誤原因

三、解決方案

3.1 方案一

3.2 方案二


一、錯誤描述

ArrayList是java開發時經常使用的一個類,又經常碰到需要對ArrayList循環刪除元素的情況。這時候大家都不會使用foreach循環的方式來遍歷List,因爲它會拋java.util.ConcurrentModificationException異常。 Vector也同樣會報異常。比如下面的代碼:

public class ConcurrentTest {

    public static void main(String[] args) {

        List<Person> list = new ArrayList<>();

        list.add(new Person("張三", 23));
        list.add(new Person("李四", 24));
        list.add(new Person("王五", 25));
        list.add(new Person("麻六", 26));

        list.forEach(person -> {
            if (person.getAge() == 24){
                list.remove(person);
            }
        });

        System.out.println(list);
    }
}

拋出異常信息如下:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList.forEach(ArrayList.java:1252)
	at com.uiotsoft.back.iotoperation.business.ConcurrentTest.main(ConcurrentTest.java:23)

二、錯誤原因

其實,基本上所有的集合類都會有一個叫做快速失敗的校驗機制,當一個集合在被多個線程修改並訪問時,就會出現ConcurrentModificationException 校驗機制。它的實現原理就是我們經常提到的modCount修改計數器。如果在讀列表時,modCount發生變化則會拋出ConcurrentModificationException異常。這與線程同步是兩碼事,線程同步是爲了保護集合中的數據不被髒讀、髒寫而設置的。

首先java的foreach循環其實就是根據list對象創建一個Iterator迭代對象,用這個迭代對象來遍歷list,相當於list對象中元素的遍歷託管給了Iterator,你如果要對list進行增刪操作,都必須經過Iterator。iterator創建的時候modCount被賦值給了expectedModCount,但是調用list的add和remove方法的時候不會同時自動增減expectedModCount,這樣就導致兩個count不相等,從而拋出異常。

三、解決方案

以下提供兩種解決方案:

3.1 方案一

使用CopyOnWriteArrayList<>(),例如如下例子:

public class ConcurrentTest {

    public static void main(String[] args) {

        List<Person> copyList = new CopyOnWriteArrayList<>();

        copyList.add(new Person("張三", 23));
        copyList.add(new Person("李四", 24));
        copyList.add(new Person("王五", 25));
        copyList.add(new Person("麻六", 26));

        copyList.forEach(person -> {
            if (person.getAge() == 25){
                copyList.remove(person);
            }
        });

        System.out.println(copyList);
    }
}

結果正常:

3.2 方案二

使用增強for循環

public class ConcurrentTest {

    public static void main(String[] args) {

        List<Person> list = new ArrayList<>();

        list.add(new Person("張三", 23));
        list.add(new Person("李四", 24));
        list.add(new Person("王五", 25));
        list.add(new Person("麻六", 26));

        for (Person person : list) {
            if (person.getAge() == 25){
                list.remove(person);
            }
        }

        System.out.println(list);
    }
}

結果正常,請看方案1的結果。

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