ArrayList在多线程时抛出ConcurrentModificationException异常的原因和解决方法

LaTex的下载与安装(2024小白+windows系统) 本文主要介绍了Latex的下载与安装,还包括安装过程中遇到的小问题的解决。 阅读详情

下方代码抛出java.util.ConcurrentModificationException异常

下面这段代码会报 java.util.ConcurrentModificationException 并发修改异常!

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

// java.util.ConcurrentModificationException 并发修改异常!
public class ListTest {
    public static void main(String[] args) {
        List<String> list =new ArrayList<>();

        for (int i = 1; i <= 30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

查找原因的方法

IDEA中打断点调试。
在PrintStream类的void println(Object x)方法的String s = String.valueOf(x);代码上打断点,调试时按Step Into。

public void println(Object x) {
    String s = String.valueOf(x);
    synchronized (this) {
        print(s);
        newLine();
    }
}

异常产生的原因

把问题出现的范围缩小,即下方代码。注意:这里的list变量是ArrayList的对象。

for (int i = 1; i <= 30; i++) {
    new Thread(()->{
        list.add(UUID.randomUUID().toString().substring(0,5));
        System.out.println(list);
    },String.valueOf(i)).start();
}

创建了30个线程,每个线程都要先执行list.add(String e),然后执行System.out.println(list);。
下图展现了涉及的类和属性和方法。
在这里插入图片描述

下图展现了方法之间的调用,即每个线程依次会执行:
list.add(String e)->modCount++;->System.out.println(list);->Iterator<E> it = new Itr();->int expectedModCount = modCount;->it.next();->checkForComodification()->if (modCount != expectedModCount)throw new ConcurrentModificationException();

在这里插入图片描述
ConcurrentModificationException异常产生的原因:因为这30个线程使用的是同一个list,同一个list里有同一个modCount,但每个线程在打印list的时候,都会Iterator<E> it = new Itr();,并且int expectedModCount = modCount;,每个线程都产生一个it和其中的expectedModCount 。如果A线程已经做完了Iterator<E> it = new Itr();,和int expectedModCount = modCount;,然后时间片用完了,B线程获得了CPU,B线程执行了list.add(String e)使得modCount++;,然后,当A线程再次获得CPU的时候,B线程在打印list的过程中,执行了it.next();方法,然后进入了checkForComodification()方法,发现modCount != expectedModCount(因为modCount已经被A线程增大了),于是抛出ConcurrentModificationException。

找出原因的具体步骤

list.add()

ArrayList类中的add()方法中,modCount++;

ArrayList类中的add()方法如下,注意modCount加一了。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

这个modCount继承自AbstractList<E>类,继承来了int modCount

AbstractList类里的变量:

protected transient int modCount = 0;

ArrayList类继承AbstractList类,即继承来了int modCount 这个变量。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
System.out.println(list);

System.out.println(list);,导致进入PrintStream类的void println(Object x)方法:

    public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }

由上方代码的String.valueOf(x);进入String类的String valueOf(Object obj)方法:

    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

由上方代码的obj.toString();进入AbstractCollection类的String toString()方法:

    public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

由上方代码的Iterator it = iterator();进入了ArrayList类的iterator()方法

    public Iterator<E> iterator() {
        return new Itr();
    }

由上方代码的new Itr();使得int expectedModCount = modCount;。Itr是ArrayList类的内部类。

    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

返回到toString()方法。

    public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

由上方代码的E e = it.next();进入ArrayList类的内部类Itr的next()方法。

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

由上方代码的checkForComodification();进入ArrayList类的内部类Itr的checkForComodification();方法。就在这里抛出ConcurrentModificationException异常。

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

解决方法

解决方案:把 List<String> list =new ArrayList<>();改为下方三个中的一种。

  • 1、List<String> list = new Vector<>();
  • 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
  • 3、List<String> list = new CopyOnWriteArrayList<>();

参考

java.util.ConcurrentModificationException异常分析及解决_学而不思则罔 思而不学则殆-优快云博客
idea中的Diagram功能,查看类图_qq_36555038的博客-优快云博客

《QT+PCL》点云配准进阶——GROR配准 GROR点云配准 阅读详情

相关推荐

Qt5.15.2安卓开发环境配置保姆级教程(含JDK8、SDK33、NDK21.4及Gradle国内镜像避坑指南)

本文提供Qt5.15.2安卓开发环境配置的完整教程,涵盖JDK8、SDK33、NDK21.4及Gradle国内镜像设置,帮助开发者快速搭建开发环境并避免常见问题。通过详细步骤和实战技巧,解决依赖冲突、网络超时等难题,提升开发效率。

weixin_28730353的博客 203

ArrayList引起的ConcurrentModificationException 异常原因及解决方法

ArrayList引起的ConcurrentModificationException 异常原因及解决方法

lhl6688的专栏 4163

【RT-Thread】从零到一:RT-Thread Studio工程创建与程序下载全流程实战

本文详细介绍了RT-Thread Studio开发环境的安装与使用,从工程创建到程序下载的全流程实战指南。通过具体案例演示了如何在STM32平台上快速开发RT-Thread应用,包括时钟配置、内存优化、构建调试等关键技巧,帮助开发者高效完成嵌入式系统开发。

weixin_30336061的博客 542

【集合】ArrayList异常ConcurrentModificationException原因及解决办法

1.并发不安全—并发修改异常 今天遍历并删除ArrayList中的map时遇到了这个问题:并发修改异常 代码大概如下: for(Map<String, Object> resultMap: list){ if (...){ list.remove(resultMap); } } 看一下这段代码的字节码文件: Iterator var6 = list.iterator(); while(true) { Map resultMap; if (!var6

ZMXQQ233的博客 1696

SpringDoc 基本使用指南

SpringDoc 凭借零配置启动注解简洁和深度兼容 Spring 生态的优势,已成为 Spring Boot API 文档的首选工具。自动化- 减少手动维护文档的成本;标准化- 严格遵循 OpenAPI 3 规范;可扩展- 分组、安全控制灵活适配复杂项目。访问即可查看交互式文档(默认路径)

墨鸦的博客 1万+

文华财经公式编程:麦语言简介及基础语法

文华财经公式语言(麦语言)是一种专门用于金融领域的编程语言,它是由文华财经公司开发的。提供了丰富的金融计算函数和数据处理功能,可以用于金融市场的数据分析、模型建立和交易策略的开发。例1:A:CLOSE;// 定义变量A为收盘价(盘中k线没有走完的时候A为最新价)。例2:MA5:=MA(C,5);// 定义收盘价的5周期均线(C为CLOSE简写)。例3:A:=REF(C,1);// 取得前一根k线的收盘价。

超哥量化的博客 1万+

ArrayList 的 ConcurrentModificationException 异常解析

在使用ArrayList,改变数组size时,我们经常会遇到ConcurrentModificationException异常,如代码三 根据 log日志可知,改异常是通过Itr类的checkForComodification方法抛出。下面我们来看一下Itr类,如代码四 出现这种问题的原因是在迭代ArrayList元素时,对元素进行增加或删除,导致modCount != expectedModCount不相等,抛出异常。 初始时,modCount = 0 // Ar...

sinat_41712356的博客 1657

VisionTransformer改进(11):结合CoordAtt注意力机制

​​CoordAtt模块​​:一个轻量级的坐标注意力机制​​ViT模型​​:基于标准Vision Transformer架构,但集成了CoordAtt模块模型最终通过CNNModel函数封装,虽然名称是CNN,但实际上是一个Transformer模型。引入了轻量级的CoordAtt注意力机制,增强了模型对空间位置信息的捕捉能力保持了ViT的主要优势,同时通过注意力机制提升了特征表示能力设计简洁高效,适合作为基础模型进行进一步研究和应用。

2401_82355416的博客 701

ArrayList删除元素时导致的java.util.ConcurrentModificationException错误的分析及源码解读

集合对于开发者来说都不陌生,可以说是我们日常开发中使用最频繁的对象之一,尤其是ArrayList,可是对于一些开发者并不真正了解它,只是使用习惯了,也就按照集合中基础的一些api使用了,但有时候却因为错误的使用集合导致代码的性能较差,甚至出现致命错误的代码。前几天在做代码review的时候,发现有同事提交了这么一段代码,它的意图就是从文章列表中删除标题不合法的的文章。这位同事还不是很服气,觉得这么写没多大问题,之前很多代码就是这么写的啊。基于此,我们从头分析一下。

泗水长流的博客 1230

Yolo8行人车辆目标检测实战分享 完整项目代码可直接运行

Yolo8行人车辆目标检测实战分享 完整项目代码可直接运行

1294

回归预测 | MATLAB实现基于贝叶斯线性回归(Bayesian Regression)的多变量输入回归预测

回归预测 | MATLAB实现基于贝叶斯线性回归(Bayesian Regression)的多变量输入回归预测

机器学习之心的博客,关注并私信文章链接,获取对应文章源码和数据。 2199

list操作中的 ConcurrentModificationException 处理

当使用for循环遍历list的时候,根据上面的代码可以知道,一开始的时候保存了一个expectedModCount这个的初始值为初始的modCount,如果在遍历过程中出现了修改list的长度,就会出现modCount值的改变(非迭代器的方法),则在下一次的遍历过程中就会出现两个值的不相等,就会抛出ConcurrentModificationException错误。这其实是集合的fasfail机制。多线程的情况下,本质是一个线程在遍历的时候,另一个线程对list进行了修改,才导致了这样的问题。

qq_44166712的博客 1022

用 ABAP 驾驭 OAuth 2.0:从 Authorization Code 到 SAML Bearer 的全栈落地指南

ABAP平台OAuth 2.0客户端开发实践 本文为SAP开发者详细解析ABAP平台内置OAuth 2.0客户端的使用方法,涵盖四种授权流的最佳实践: 授权流选择: Authorization Code:适用于用户交互场景 SAML 2.0 Bearer:适合已有SAML体系的企业 Client Credentials:系统间通信 Password Credentials:过渡方案(不推荐) 配置流程: 通过SE80定义Client Profile 使用SOAUTH2_CLIENT/OA2C_CONFIG配

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 309

Java ConcurrentModificationException异常原因和解决方法

  在前面一篇文章中提到,对Vector、ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常。下面我们就来讨论以下这个异常出现的原因以及解决办法。   以下是本文目录大纲:   一.ConcurrentModificationException异常出现的原因   二.在单线程环境下的解决办法   ...

一尘在心的博客 658

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

java.util.ConcurrentModificationException解决详解

异常产生 当我们迭代一个ArrayList或者HashMap时,如果尝试对集合做一些修改操作(例如删除元素),可能会抛出java.util.ConcurrentModificationException的异常。 package reyo.sdk.utils.test.list2; import java.util.ArrayList; import java.util.L...

285

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

concurent modifaction 异常

https://www.cnblogs.com/dolphin0520/p/3933551.html   在前面一篇文章中提到,对Vector、ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常。下面我们就来讨论以下这个异常出现的原因以及解决办法。   以下是本文目录大纲:   一.Concu...

qq_39018929的博客 346

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

ConcurrentModificationException学习记录

ConcurrentModificationException位于java.util包下,中文意思就是并发修改异常。 当一个线程在遍历集合时,另一个线程对集合进行修改(添加或删除元素),此时遍历过程可能会出现问题。为了避免这类问题,某些迭代器在检测到这种情况时会抛出ConcurrentModificationException,这些迭代器就叫做fail-fast(快速失败)迭代器。 注意:此异常并不总是表示对象被不同的线程同时修改。 如果单个线程使用违反对象合同的方法调用集合,也可能会抛出此异常。 例如,

椿尼的博客 779

List遍历时删除与迭代器(Iterator)解惑

文章目录ArrayList 遍历时删除方法for循环向后遍历的陷阱增强型for循环(foreach)遇到的问题使用迭代器进行遍历同时修改操作iterator调用remove()方法为什么要先调用next()方法?快速失败(fail-fast)安全失败(fail-safe) List集合使我们非常熟悉的,ArrayList等集合为我们提供了remove()方法,但在遍历时却不能随便使用,我们我们今天便从实现层面讨论下原因以及Iterator的相关知识。 ArrayList 遍历时删除方法 for循环向后遍历的

qq_40776361的博客 2838

ConcurrentModificationException异常原因和解决方法

首先看一下一个例子举出 ConcurrentModificationException 的出现场景: public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(){ { add(1); add(2); add(3); } }; Iterator&

qq_44613591的博客 9万+

java.util.ConcurrentModificationException异常原因及解决方法

java.util.ConcurrentModificationException异常原因及解决方法 在java语言中,ArrayList是一个很常用的类,在编程中经常要对ArrayList进行删除操作,在使用remove方法对ArrayList进行删除操作时,报java.util.ConcurrentModificationException异常,下面探讨一下该异常的原因以及解决办法。 import java.util.ArrayList; import java.util.List; public c

java0825的博客 6万+

java.util.ConcurrentModificationException异常出现的原因及解决方法

增强for循环 遍历列表时会调用 checkForComodification() 方法检查当前列表是否有并发修改,如果有则会抛出 java.util.ConcurrentModificationException 异常。

晴空๓ 2995
上一篇: Redis第一弹(1-13集)
下一篇: 优快云插入视频和插入gif
夜中听雪
博客等级 码龄8年 230粉丝 69原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值