ConcurrentModificationException并发修改异常产生的原因及解决方案

17 篇文章 1 订阅
15 篇文章 0 订阅

异常名称:

ConcurrentModificationException并发修改异常


问题描述

当调用了集合本身增删过程中出现并发修改异常:

当我们在遍历实现了collection接口与iterator 接口的集合时(List、Set、Map), 我们可以通过遍历索引也可以通过迭代器进行遍历。在我们使用迭代器进行遍历集合的时候,会获取到当前集合的迭代对象。在里面有封装了迭代器的remove方法与集合自带的remove方法,如果我们调用迭代器对象的remove方法是没问题的,但是当我们调用集合自带的remove方法时,就会产生ConcurrentModificationException 并发修改异常。也就是说,当我们通过非迭代器进行遍历集合的时候,是不允许集合本身在结构上发生变化的。

举例说明-代码

案例演示需求:

//案例演示需求:
//我有一个集合,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。
 List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("world");
        list.add("d");
        list.add("e");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("--------------");
 for (Object o : list) {
            if (o.equals("a")){
                list.remove(o);
            }
        }

// 以为为map的例子



TreeMap<Car, String> treeMap = new TreeMap<>();
        //添加元素
        treeMap.put(new Car("奔驰", 1200000), "zhangsan");
        treeMap.put(new Car("宝马", 800000), "lisi");
        treeMap.put(new Car("三菱", 50000), "zhaoliu");
        treeMap.put(new Car("三8菱", 500), "zhaoliu");
        treeMap.put(new Car("丰田", 150000), "wangwu");
        for (com.dljd.day12.user.HomeWork01.Car car : treeMap.keySet()) {
            System.out.println(car);
        }
        //TODO
        System.out.println("---------------------------------");
        for (com.dljd.day12.user.HomeWork01.Car car : treeMap.keySet()) {
            if (car.price < 100000)
                treeMap.remove(car);
        }
        for (com.dljd.day12.user.HomeWork01.Car car : treeMap.keySet()) {
            System.out.println(car);
        }

public class Car implements Comparable<Car> {
    String carName;
    int price;

    public Car(String carName, int price) {
        this.carName = carName;
        this.price = price;
    }

    public Car() {
    }

    @Override
    public String toString() {
        return "Car{" +
                "carName='" + carName + '\'' +
                ", price=" + price +
                '}';
    }

    @Override
    public int compareTo(Car car) {
        return car.price - this.price;
    }

在这里插入图片描述


原因分析:

根据追踪源码发现,并发修改异常是因为,在集合中增删操作会导致 预期数量计数器的数量不一致,就会导致并发修改异常

在这里插入图片描述


解决方案:

1.普通for循环可解决

      List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("world");
        list.add("d");
        list.add("e");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("--------------");
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).equals("a")) {
                list.remove(i);
            }
            System.out.println(list.get(i));
        }

2.list集合有一个listIterator的迭代器可以进行元素添加

package com.heima.list;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class Demo03_List {

	/**
	 * * A:案例演示
	 * 需求:我有一个集合,请问我想判断里面有没有"world"这个元素.如果有,我就添加一个"javaee"元素,请写代码实现.
	 */
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("a");								//Object obj = new String();
		list.add("b");
		list.add("world");
		list.add("c");
		list.add("d");
		list.add("e");
		
		/*Iterator it = list.iterator();			//获取迭代器
		while (it.hasNext()) {						//判断集合中是否有元素
			String str = (String) it.next();		//向下转型
			if ("world".equals(str)) {
				list.add("javaee");					//遍历的同时在增加元素,并发修改ConcurrentModificationException
			}
		}*/
		
		ListIterator lit = list.listIterator();		//获取迭代器(List集合特有的)
		while (lit.hasNext()) {
			String str = (String)lit.next();		//向下转型
			if ("world".equals(str)) {
				//list.add("javaee");				//遍历的同时在增加元素,并发修改ConcurrentModificationException
				lit.add("javaee");
			}
		}
		System.out.println(list);
	}
}


特例:

删除list集合中倒数第二个元素时,不会报出并发修改异常,但仅仅适用于list,map集合依然会报出并发修改异常

 public static void main(String[] args) {
        List<String> list = new ArrayList<>();
//        LinkedList<String> list = new LinkedList<>();
/**
 * list执行add的时候,计数器modCount++ 自增(从0开始)(集合不管增或者删计数器都会自增+1)
 */
        list.add("1");
        list.add("3");
        list.add("8");
//此时计数器modCount=2
        for (String s : list) {
/**
 * 增强for循环,for和while都是关键字,编译的时候,会使用迭代器,底层是迭代器,Iterater
 * list集合实现类ArrayList中初始化迭代器的时候,会把计数器modCount赋值给迭代器的计数器
 * expectedModCount = modCount
 * 每次获取下一个元素的时候,先判断if (modCount != expectedModCount),如果不相等,则抛出并发修改异常
 * ConcurrentModificationException
 */
            if (s.equals("3")) {
                list.remove(s);
            }
/**
 * 特例:当删除集合中倒数第二个元素时
 * 在循环中删除1的时候没有抛出并发修改异常
 * 因为,每次进行下一次循环的时候,调用hasNext方法,判断是否有下一个元素。
 * 根据当前遍历的索引位置和集合长度比较,如果索引位置等于集合长度了,表示遍历完了(否则就会数组越界)
 * 因为删除0索引位置的数据,集合长度是1,索引位置也是1,于是相等,循环结束。
 */
        }

        for (String s : list) {
            System.out.println(s);
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值