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

Posted 后端研发Marion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA开发日常问题三多线程遍历集合报错java.util.ConcurrentModificationException: null相关的知识,希望对你有一定的参考价值。


一、问题出现

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

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

二、问题分析

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

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

三、问题解决

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. 类变量是分配在堆内存空间上面的,内存共享,所以多个线程操作是同一块内存。

 

以上是关于JAVA开发日常问题三多线程遍历集合报错java.util.ConcurrentModificationException: null的主要内容,如果未能解决你的问题,请参考以下文章

java多线程同时向一个数组arraylist添加元素,遍历这个集合

Java集合框架中的快速失败(fail—fast)机制详解

Java中List集合的三种遍历方式(全网最详)

Java8使用Stream API转换Map遇到的2种异常报错和解决思路

ArrayList和LinkedList介绍

Arraylist 三种常用遍历