首页 > 其他分享 >如何解决ConcurrentModificationException的异常!

如何解决ConcurrentModificationException的异常!

时间:2022-12-15 11:00:53浏览次数:42  
标签:modCount ConcurrentModificationException ArrayList subList sourceList newList 解决

一. 前言

在使用使用ArrayList的subList的时候,发生了ConcurrentModificationException的异常。接下来看看如何处理

二. 异常场景

2.1 代码如下

下面是产生异常的代码。

public static void main(String[] args) throws InterruptedException {

    // 1 定义一个String的集合,并且添加3个元素 【"z","k","x"】
    List<String> sourceList = new ArrayList<String>(2);
    sourceList.add("z");
    sourceList.add("k");
    sourceList.add("x");
    // 2 使用subList方法 表面上把集合的前2个元素截取出来放在新的集合newList中
    // 表面上此时newList 应该是【"z","k"】
    List<String> newList = sourceList.subList(0, 2);
    // 3 往sourceList的0号位置 添加新的元素 sourceList应该变成了 【“cs”,"z","k",“x”】
    sourceList.add(0,"cs");
    // 4 意图在控制台上打印新的集合newList的0号位置 想观察一次此时newList的0号元素到底是什么
    // 结果如果是 "z" 说明:【newList 是 sourceList的副本,此时两者已经没什么关系】
    // 结果如果是 "cs"  说明:【newList 是 sourceList的视图,修改sourceList会影响到newList】
    // 结果意想不到的是 这个地方抛出了ConcurrentModificationException 异常
    System.out.println(newList.get(0));
}

2.2 异常截图

三. 原因分析

3.1 modCount变量

ArrayList 的父类AbstractList中定义了一个变量modCount,顾名思义这个变量就是用来记录ArrayList被修改的次数,modCount 初始值为0,ArrayList 源代码如下。

protected transient int modCount = 0;

3.2 modCount解析

ArrayList 中每每有增删改的变动,都会导致modCount加1,源代码如下。

// 例如 ArrayList 的 add 方法
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!! 在这里modCount+1
    elementData[size++] = e;
    return true;
}

// 继续深入到 ensureCapacityInternal 方法
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);   // 在这里modCount+1 这里再继续深入
}

// 继续深入到ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

3.3 SubList源码

ArrayList 使用SubList的时候并没有创建新的List,而是引用原来的List,并且把原本List的modCount复制了过来,源代码如下。

图片

3.4 ConcurrentModificationException异常产生原因

subList在做增删改查时都会对比一下自己的modCount 和 原生的list的modCount如果对应不上就会抛出ConcurrentModificationException异常源代码如下

// subList的get 方法 调用之前要checkForComodification
public E get(int index) {
    rangeCheck(index);
    checkForComodification();
    return ArrayList.this.elementData(offset + index);
}

// 跟入到checkForComodification
private void checkForComodification() {
    // 比较subList 的modCount 和 源list的modCount 不相等等则抛出异常
    if (ArrayList.this.modCount != this.modCount)
        throw new ConcurrentModificationException();
}

四. 结论和解决方案

4.1 原因总结

至此,我们在上面代码中发生异常的原因已经一目了然了,再来看一下源代码:

图片

4.2 解决方案

为了避免出现ConcurrentModificationException异常,我们在开发时要慎用subList,可以自行使用stream来截取需要的部分。

// List<String> newList = sourceList.subList(0, 2);
// 使用流的方式代替subList截取
List<String> newList = sourceList.stream().skip(0).limit(2).collect(Collectors.toList());

可以对subList 进行二次封装,封装成一个新的ArrayList。

List<String> newList = sourceList.subList(0, 2);
// 对subList的结果,再次封装成新的List
ArrayList newList1 = new ArrayList<>(newList);

五. 后话

其实上面的这个异常问题,在阿里巴巴的开发规范中早有说明,原文如下:

【强制】在 subList 场景中,高度注意对原集合元素的增加或删除,均会导致子列表的遍历、 增加、删除产生 ConcurrentModificationException 异常。

标签:modCount,ConcurrentModificationException,ArrayList,subList,sourceList,newList,解决
From: https://www.cnblogs.com/xsl-soul/p/16984492.html

相关文章

  • VNC常用操作及常见问题解决办法汇总
     VNC登录用户缺省是root,但在安装oracle时必须用oracle用户的身份登录,下面我们就以oracle为例说明如何配置VNC,从而可以使用不同的用户登录到主机。步骤描述如下:   步骤......
  • uniapp vue3下的代理转发不生效问题,亲测有效解决
    以前配置过vuevite的代理转发,没想到在uniapp的代理转发下翻车了,其实是一个很小的问题。调试过程中,尝试了webpack、vite等写法在根目录下创建了vite.config.jsvue.co......
  • 【弹出USB大容量存储设备时出问题】解决方法
    问题:【弹出USB大容量存储设备时出问题】-有程序正在使用USB设备无法弹出解决:打开事件查看器-管理事件,查看出错信息(双击) 找到占用的进程PID为5988:打开任务管理器......
  • Twincat3在64位操作系统运行,报错 VT-X extension not enabled或在VMWare虚拟机上运行
    1、首先,在64位的操作系统当中运行TC3PLC,必须要进到BIOS当中使能VT-x.因为TC3说明书中明确提到64位系统要运行TC3,VT-X是必须要支持的。2、[可选]在【控制面板】......
  • webpage页面打开速度变慢--Session阻塞造成时的解决方案(转)
    Asp.net项目因Session阻塞导致页面打开速度变慢    前年有个Asp.net项目上线后,正常情况下大部分页面打开速度都很快,但个别页面处理速度较慢。奇怪的是一旦访问个别......
  • 异常总结
    1、异常语法try:可能发生异常的代码except:如果出现异常执行的代码else:没有异常执行的代码finally:无论是否异常都......
  • 异常
    一、了解异常当检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”。二、异常的写法2.1语法try:可......
  • 缺页异常
     程序存储在disk,在32位系统下,虚拟地址空间最大4G,但是不是每个地址都存储程序片段。上图左侧是一整个虚拟地址空间,没有程序片段的地址空间称为Unallocated;有程序片段,并且......
  • ogg目标库应用进程异常,告警OGG-00519、ORA-02443
    问题描述:ogg目标库应用进程异常,告警OGG-00519、ORA-02443,如下所示:场景说明:源端表中存在一个约束,约束名为系统自定义,该约束在目标端未能查找,所以便在源库将其删除,结果就出现......
  • 老版本word文档打开文字重叠、重影解决方法
    [文章推荐]每日一练:Python数据爬取与地图绘制老版本的word文档用新版本的word打开经常会出现文字重叠的现象。解决方法:全选之后修改字体即可。......