首页 > 其他分享 >并发修改异常 ConcurrentModificationException详解

并发修改异常 ConcurrentModificationException详解

时间:2024-08-11 20:28:10浏览次数:19  
标签:并发 ConcurrentModificationException ArrayList 修改 modCount 详解 l2 异常

并发修改异常 ConcurrentModificationException详解

  • 异常产生原因:并发修改异常指的是在并发环境下,当方法检测到对象的并发修改,但不允许这种修改时,抛出该异常。

  • 异常抛出在ArrayList类中的checkForComodification()方法中。

  • checkForComodification()方法实际上就是当modCount 变量值不等于expectedModCount变量值时,就会触发此异常。

  • modCount :AbstractList类中的一个成员变量,由于ArrayList继承自AbstractList,所以ArrayList中的modCount变量也继承过来了。

  • expectedModCount:是ArrayList中内部类Itr的一个成员变量,当我们调用iterater()获取迭代器方法时,会创建内部类Itr的对象,并给其成员变量expectedModCount赋值为ArrayList对象成员变量的值modCount【预期修改次数】。

  • 查看ArrayList的源码可知,modCount 初始值为0, 每当集合中添加一个元素或者删除一个元素时,modCount变量的值都会加一,表示集合中结构修改次数多了一次

解决方案

当用迭代器遍历元素时,集合不能修改,但是迭代器可以修改

由上图可知,modCount和expectedModCount会一直相等,所以不会抛出异常

举例:使用List集合存储字符串元素,使用迭代器遍历,遍历的时候,如果遇到"java",就向集合中添加一个元素"shujia"

import java.util.ArrayList;
import java.util.ListIterator;
public class ListDemo1 {
    public static void main(String[] args) {
        ArrayList l2 = new ArrayList();
        l2.add("hello");
        l2.add("java");
        l2.add("world");
        l2.add("hello");
        System.out.println(l2);
        System.out.println("===============");
        ListIterator listIterator = l2.listIterator();
        while (listIterator.hasNext()){
            Object o = listIterator.next();
            String s = (String) o;  //下转型。因为Object类没有equals()方法
            if (s.equals("java")){
                listIterator.add("shujia"); //List迭代器追加
            }
        }
        System.out.println(l2);
    }
}


拓展:当要删除的元素在集合中的倒数第二个元素的时候,删除元素不会产生并发修改异常。
原因:因为在调用hasNext()方法的时候,cursor = size是相等的,hasNext()方法会返回false, 所以不会执行next()方法,也就不会调用checkForComodification()方法,就不会发生并发修改异常。

小结论:

  1. 迭代器调用remove()方法删除元素,底层还是调用的集合的删除元素的方法;
  2. 在调用remove()方法后,都会将modCount的值赋值给expectedModCount,保证了它两的值永远都是相等的,所以也就不会产生并发修改异常;

标签:并发,ConcurrentModificationException,ArrayList,修改,modCount,详解,l2,异常
From: https://www.cnblogs.com/zhuzhuya/p/18353835

相关文章

  • MySQL 数据类型详解
    MySQL是一种广泛使用的关系型数据库管理系统,它支持多种数据类型以满足各种应用场景的需求。本文将详细介绍MySQL支持的数据类型、它们的使用场景以及实现原理,并通过图示帮助读者更直观地理解。目录简介数值类型整型浮点型定点型日期和时间类型字符串类型字符串二进制字......
  • Redis 数据类型详解
    Redis是一个开源的内存数据结构存储系统,广泛应用于缓存、消息队列、实时数据分析等场景。Redis提供了多种数据类型,本文将详细介绍Redis的五种主要数据类型及其应用场景,并从概述、基本操作、应用场景和数据结构等方面进行深入探讨。1.字符串(String)概述字符串是Redis......
  • Redis 数据类型详解
    Redis是一个开源的内存数据结构存储系统,广泛应用于缓存、消息队列、实时数据分析等场景。Redis提供了多种数据类型,本文将详细介绍Redis的五种主要数据类型及其应用场景,并从概述、基本操作、应用场景和数据结构等方面进行深入探讨。1.字符串(String)概述字符串是Redis......
  • MySQL 数据类型详解
    MySQL是一种广泛使用的关系型数据库管理系统,它支持多种数据类型以满足各种应用场景的需求。本文将详细介绍MySQL支持的数据类型、它们的使用场景以及实现原理,并通过图示帮助读者更直观地理解。目录简介数值类型整型浮点型定点型日期和时间类型字符串类型字符串二进制字......
  • 公主少爷都爱看的haproxy七层代理详细介绍及常见实验详解
    目录一、负载均衡1.1什么是负载均衡1.2为什么要实验负载均衡1.3四层负载均衡1.4七层负载均衡1.5四层负载均衡和七层负载均衡的对比二、什么是haproxy2.1定义2. 2功能和特点2.3应用场景 2.4haproxy的分类 三、安装及基本配置的信息3.1软件的安装3.2haproxy基本......
  • C++虚函数表、地址详解(x86/x64)
    参考博文:c++虚函数表、地址详解-CSDN博客本文在上述博文的基础上,补充了x64下的验证代码。一.什么是虚函数表,它有什么特点?        虚函数大家都知道是基本用于实现多态的,当父类指针指向子类对象的时候,如何确定调用的函数是父类里的还是子类里面的,这就要用到虚函数表......
  • C语言——最强版操作符详解
    1.操作符的分类•算术操作符:+、-、*、/、%•移位操作符:<<>>•位操作符:&|^•赋值操作符:=、+=、-=、*=、/=、%=、<<=、>>=、&=、|=、^=•单⽬操作符:!、++、–、&、*、+、-、~、sizeof、(类型)•关系操作符:>、>=、<、<=、==......
  • JS【详解】数据类型检测(含获取任意数据的数据类型的函数封装、typeof、检测是否为 nul
    【函数封装】获取任意数据的数据类型/***获取任意数据的数据类型**@paramx变量*@returns返回变量的类型名称(小写字母)*/functiongetType(x){//获取目标数据的私有属性[[Class]]的值constoriginType=Object.prototype.toString.call(x);//......
  • PostgreSQL的WAL日志详解
    PostgreSQL的WAL日志详解1.WAL日志介绍1.1WAL介绍wal日志即writeaheadlog预写式日志,简称wal日志。wal日志可以说是PostgreSQL中十分重要的部分,相当于oracle中的redo日志。当数据库中数据发生变更时:change发生时:先要将变更后内容计入walbuffer中,再将变更后的数据写入data......
  • 操作符详解2(第22天)
    4.赋值操作符:=,+=,-=,*=,/=,>>=,<<=,%=等等 你可以给自己重新赋值!!注意如a=b=c+1它是从右到左开始计算的,最好拆开写更好一些两种等价写法a=a+100,a+=100!!一个=叫赋值两个==叫判断5.单目操作符:!(逻辑反操作),-,+,&(取地址),sizof(求字符长度),~(对一个数的二进制按位取反),--,++,*(间接访问操作符)......