【JAVA开发日常问题】三、多线程遍历集合报错java.util.ConcurrentModificationException: null

一、问题出现

突然发现线上某段代码报错,报错内容Unhandled exception caught java.util.ConcurrentModificationException: null

二、问题分析

1. 网上了找了些文章,关于这个错误的解释java.util.ConcurrentModificationException 异常原因和解决方法,大概了解到对集合元素遍历的时候删除或者新增会导致这个异常<font color=red>迭代器的modCount和expectedModCount的值不一致</font>

2. 但是我的业务代码没有做新增操作和删除操作,所以元素遍历不应该报错。代码如下:

    private List<UserInfo.ImageInfo> createImageInfo(List<UserImageEntity> imageEntities) {
        List<UserInfo.ImageInfo> images = new ArrayList<>();
        if (imageEntities != null) {
            Iterator<UserImageEntity> iterator = imageEntities.iterator();
            while(iterator.hasNext()){
                UserInfo.ImageInfo image = createImageInfo(iterator.next());
                images.add(image);
            }
        }
        return images;
    }

3. 于是乎我猜想既然是<font color=red>迭代器的modCount和expectedModCount的值不一致</font>会导致这个异常发生,那么会不会是多线程遍历静态类成员变量的时候而发生的异常呢,于是我写了一段测试代码,如下:

package collection;

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

/**
 * @author Marion
 * @date 2020/8/20
 */
public class ArrayListDemo {

    private static List<UserModel> list = new ArrayList<>();

    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        for (int i = 0; i < 3; i++) {
            Thread mThread1 = new Thread(thread1, "线程" + i);
            mThread1.start();
        }
    }

    public static void testUserModel() {
        list.add(new UserModel(1));
        list.add(new UserModel(2));
        list.add(new UserModel(3));
        createImageInfo(list);
    }

    public static class MyThread implements Runnable {
        @Override
        public void run() {
            testUserModel();
        }
    }

    private static List<UserModel> createImageInfo(List<UserModel> imageEntities) {
        List<UserModel> images = new ArrayList<>();
        if (imageEntities != null) {
            Iterator<UserModel> iterator = imageEntities.iterator();
            while (iterator.hasNext()) {
                UserModel image = createImageInfo(iterator.next());
                System.out.println("imageEntities = [" + image.toString() + "]");
                images.add(image);
            }
        }
        System.out.println("imageEntities size = [" + images.size() + "]");
        return images;
    }

    public static UserModel createImageInfo(UserModel userModel) {
        return userModel;
    }

    public static class UserModel {
        private int id;

        public UserModel() {
        }

        public UserModel(int id) {
            this.id = id;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "UserModel{" +
                    "id=" + id +
                    '}';
        }
    }
}

4. 上面代码运行结果然报错了,和线上的区别在于线上是从线程池报错,只是我为了测试方便用的手动创建线程。

三、问题解决

1. 找到问题之后,就可以给方法加锁控制线程安全synchronized解决了。代码如下:

    private synchronized List<UserInfo.ImageInfo> createImageInfo(List<UserImageEntity> imageEntities) {
        List<UserInfo.ImageInfo> images = new ArrayList<>();
        if (imageEntities != null) {
            Iterator<UserImageEntity> iterator = imageEntities.iterator();
            while(iterator.hasNext()){
                UserInfo.ImageInfo image = createImageInfo(iterator.next());
                images.add(image);
            }
        }
        return images;
    }

四、总结

1. 对于类集合变量的遍历如果是单线程执行没有问题,但是多线程情况下会报错,是因为迭代器的modCount和expectedModCount的值不一致,其他线程修改了modCount,但是当前线程比对错误,而报错ConcurrentModificationException。

2. 类变量是分配在堆内存空间上面的,内存共享,所以多个线程操作是同一块内存。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个 Java 异常,表示在迭代集合时,出现了并发修改异常。这通常发生在使用 for-each 循环、迭代器或者 Stream API 遍历集合时,同时在修改集合中的元素。在多线程环境下,如果多个线程同时对集合进行修改,也可能出现这个异常。解决该异常的方法是使用迭代器的 remove() 方法或者使用并发集合类(如 ConcurrentHashMap)来避免同时对集合进行修改。 ### 回答2: java.util.ConcurrentModificationExceptionJava 中的一个异常类,它表示在使用迭代器遍历集合的同时,该集合的内容发生了修改。通常情况下,当使用迭代器遍历一个集合,而在遍历过程中对集合的内容进行了增删操作,就会抛出此异常。 在具体的异常信息 "null" 表示引发异常的代码行未正确定义或未返回具体异常信息,导致无法显示异常的详细信息。 为了避免出现这个异常,我们可以采取以下几种方式: 1. 使用迭代器的 remove() 方法删除元素,而不是直接使用集合的 remove() 方法,因为后者可能会改变集合的结构。 2. 在使用迭代器遍历集合的时候,如果需要对集合进行修改操作,应该使用迭代器的 add()、remove() 等方法进行操作。 3. 如果在多线程环境下使用了迭代器,可以使用 synchronized 关键字或者使用并发集合类(如 ConcurrentHashMap)来保证多线程操作的安全性。 总之,java.util.ConcurrentModificationException 出现的原因是在遍历集合的过程中,对集合进行了修改操作。我们可以通过使用迭代器的方法来添加、删除元素,或者使用并发集合类来避免这个异常的发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值