首页 > 编程语言 >多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationException 异常

多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationException 异常

时间:2024-05-17 14:18:35浏览次数:14  
标签:java ConcurrentModificationException ArrayList remove add integer 多线程 listA arra

在说多线程操作List之前,我们先看下单线程下产生的问题:

单线程

List<Integer> listA=new ArrayList<>();
listA.add(1);
listA.add(2);
listA.add(3);
listA.add(4);
listA.add(5);
listA.add(6);


for(Integer a:listA){
  if (a==3) {
    listA.remove(3);
  }
}

//再次使用集合就会报错

System.out.println("list元素:" + listA);

该段代码最终会抛出  java.util.ConcurrentModificationException 错误,主要的原因是:

在List循环时,会初始化modCount=0;当该集合进行增加、删除操作值,modCount会自增;而我们使用加强for循环时候,会把modCount初始化的值给迭代器中的expectedModCount,也就是说开始expectedModCount也是为0;但是当集合操作了新增元素,modCount++ ,但是expectedModCount没有新增。导致modCount和expectedModCount不一致,当我们再次访问这个原集合时候,就会抛出java.util.ConcurrentModificationException 错误。

多线程

 说明:subList 返回的是 ArrayList 的内部类 SubList,并不是ArrayList ,而是 ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上,对SubList操作,其实也是对ArrayList 操作,比如删除SubList中的元素,同时也会删除ArrayList 的元素。 在subList场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。

List<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        arrayList.add(5);
        arrayList.add(6);


        Thread t1= new Thread(new Runnable() {
            @Override
            public void run() {
                List<Integer> list = arrayList.subList(0, 3);
                for (Integer integer : list) {
                    System.out.println(" "+integer);
                    if(integer == 2){
                        list.remove(integer);
                    }
                }
                System.out.println("进行元素的删除操作");
                //arrayList.remove(4);
                System.out.println("list元素:" + list);
            }
        });
        Thread t2= new Thread(new Runnable() {
            @Override
            public void run() {
                List<Integer> list2 = arrayList.subList(4, 6);
                for (Integer integer : list2) {
                    System.out.println(" "+integer);
                    if(integer == 4){
                        list2.remove(integer);
                    }
                }
                System.out.println("进行元素的删除操作");
                //arrayList.remove(4);
                System.out.println("list元素:" + list2);
            }
        });
        t1.start();
        t2.start();

 

ArrayList中有个protected transient int modCount = 0; 用来记录当前ArrayList被修改的次数。

比如add(),remove()等都会导致modeCount增加: ArrayList.subList()会生成一个SubList的对象,SubList中有个对应modCount同步ArrayList中的modeCount: SubList对象每次再遍历时,会将自己的modeCount与ArrayList的modeCount进行对比,如果两个值不一样就会报异常:ConcurrentModificationException

标签:java,ConcurrentModificationException,ArrayList,remove,add,integer,多线程,listA,arra
From: https://www.cnblogs.com/hhwww/p/18197585

相关文章

  • java netty 实现 websocket 服务端和客户端双向通信 实现心跳和断线重连 完整示例
    javanetty实现websocket服务端和客户端双向通信实现心跳和断线重连完整示例maven依赖<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.97.Final</version></dependency>服务端一个接口IGet......
  • java PDF转换图片(多张pdf转换成一整张图片)
    引入pdf操作相关pom <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.21</version></dependency>具体代码@RequestMappin......
  • Java枚举类
    一、使用场景:什么情况下使用枚举类?有的时候一个类的对象的个数是固定的,这种情况下我们就应该用枚举类来表示这个类。比如表示星期,就可以将Week定义为一个枚举类,同时为Week枚举类创建七个对象。再比如表示季节,就可以将Season定义为一个枚举类,同时为Season枚举类创建四个对象。......
  • java01基础入门
    java01基础入门准备javac-versionjava-versioncd..//回到上一级勾选文件扩展名设置Path环境变量IDEA创建工程开发步骤project->module->package->class设置主题、字体快捷键注释关键字基本组成:由数字、字母、下划线(_)和美元符($)等组......
  • 一个Java基于codePoint的emoji判断方法
    该方法参考自一篇博客java判断是否是emoji字符(史上最全)_Mr.QingBin的博客-CSDN博客_java判断emoji经过简单封装如下:publicclassEmojiFilter{privateEmojiFilter(){}/***过滤emoji或者其他非文字类型的字符*如果只需要判断是否含有emoji,使用hasEmoji......
  • 一个Java基于阻塞的定时消费内存队列
     @Getter@AllArgsConstructorpublicenumInsertQueueEnum{A(30000,10,TimeUnit.SECONDS,2,1000),;privatefinalintcapacity;//队列长度privatefinalinttime;//最长阻塞时间privatefinalTimeUnittimeUnit;//最长阻塞时间单位privatefi......
  • Java 网络编程(socket)
    概念:1.什么是网络编程?  计算机跟计算机之间通过网络进行数据传输。2.通信的软件架构C/S与B/S的区别?  C/S:客户端/服务端模式(需要开发客户端)  B/S:浏览器/服务端模式(不需要开发客户端)  网络编程三要素:1.IP     设备在网络中的地址,是唯一的标识2.......
  • hdu1176免费馅饼java
    一个数塔问题,以时间为纵坐标、位置为横坐标创建一个二维数组,然后从下往上相加。状态转移方程:9>=j>=1时dp[i][j]+=max(max(dp[i+1][j],dp[i+1][j+1]),dp[i+1][j-1])  j=0时 dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]) j=10时dp[i][j]+=......
  • Java-并发-ReentrantLock
    0.是什么ReentrantLock是java.util.concurrent.locks包中的一个类,提供了比synchronized关键字更灵活和强大的锁机制。ReentrantLock实现了Lock接口,它允许显式地加锁和解锁,并提供了一些高级功能,如中断锁请求、超时锁请求、公平锁和非公平锁选择等。1.为什么在Java诞生......
  • Java-线程-wait()、notify()和notifyAll()
    0.是什么(What)wait(),notify(),和notifyAll()方法都是Object类的一部分,用于实现线程间的协作。1.为什么(Why)线程的执行顺序是随机的(操作系统随机调度的,抢占式执行),但是有时候,我们希望的是它们能够顺序的执行。所以引入了这几个方法,使得我们能保证一定的顺序。1.1Objec类......