Java并发修改错误ConcurrentModificationException分析

来源:互联网 发布:mac系统画流程图 编辑:程序博客网 时间:2024/05/23 13:00

1. 介绍
并发修改ConcurrentModificationException错误是开发中一个常见错误,多发生在对一个Collection边遍历边做影响size变化的操作中,下面以ArrayList为例分析ConcurrentModificationException错误。

2. 分析
ArrayList初始数据如下。

List<Integer> list = new ArrayList<Integer>();        list.add(1);        list.add(2);        list.add(3);

场景1:不会有并发修改错误

int length = list.size();        for (int i = 0; i < length; i++) {            if (list.get(i).equals(2)) {                list.add(10);            }        }

场景2:会有并发修改错误

for(int temp : list) {            if(temp == 2) {                list.add(10);            }        }

场景3:会有并发修改错误

Iterator<Integer> iterator = list.iterator();        while(iterator.hasNext()) {            if(iterator.next().equals(2)) {                list.add(10);            }        }

场景4:没有并发修改问题

ListIterator<Integer> listIterator = list.listIterator();        while (listIterator.hasNext()) {            if (listIterator.next().equals(2)) {                listIterator.add(10);            }        }

其实ConcurrentModificationException异常的抛出是由于checkForComodification(AbstractList类中)方法的调用引起的

private void checkForComodification() {        if (this.modCount != l.modCount)            throw new ConcurrentModificationException();    }

而checkForComodification方法的调用发生在Iterator相关api方法中,
在调用list的iterator方法会创建一个Itr对象、
这里写图片描述
在创建会与AbstractList的modCount赋予相同的值, 而在Itr的next方法中会调用checkForComodification
这里写图片描述

在场景3中,list.add操作更改modCount的值,所以会有并发修改错误
而场景1中并没有使用iterator相关api,add操作虽然修改了modCount但是不会检查modCount所以没有并发修改错误。
场景4中,ListItr类add方法

 public void add(E e) {            checkForComodification();            try {                int i = cursor;                ArrayList.this.add(i, e);                cursor = i + 1;                lastRet = -1;                expectedModCount = modCount;            } catch (IndexOutOfBoundsException ex) {                throw new ConcurrentModificationException();            }        }

其中9行:在调用了list.add操作之后,将ListItr中的expectedModCount与AbstractList中的modCount进行了同步,所以在下次调用next也就不会抛出异常了,此时假如以后不调用next或者又重新创建了 ListItr也不会有异常抛出。
最后场景2并没有使用Iterator中的api为什么也抛出了异常了。其实编译器会将for-each循环代码编译为Iterator相关api的调用。
为了便于查看编译后的代码这里添加一个“———-”打印。

List<Integer> list = new ArrayList<Integer>();        list.add(1);        list.add(2);        list.add(3);        System.out.println("------------");        for (int temp : list) {            if (temp == 2) {                list.add(10);            }        }

编译后的字节码为:
这里写图片描述
所以场景2和场景3是一样的,也会抛出异常了。

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 win10驱动不尖锐怎么办 苹果内存太小怎么办 内存太小怎么办手机 苹果手机屏幕不能滑动怎么办 vivo手机软件不兼容怎么办 微信无法录音怎么办 手机卡住了怎么办vivo 好钱包闪退怎么办 闲鱼认证失败怎么办 闲鱼买了假门票怎么办 买黄金买到假的怎么办 闲鱼被买家骗了怎么办 闲鱼上小视频没法保存怎么办 qq空间无法查看怎么办 华为手机电池不耐用怎么办 内内被动过怎么办 hp电脑开机黑屏怎么办 网上开店快递费怎么办 保温杯外壳掉漆怎么办 拖鞋前面磨脚怎么办 塑料拖鞋磨脚怎么办 路由器进不去设置界面怎么办 手机号丢了微信登不上怎么办 电脑总是闪黑屏怎么办 支付宝破产钱怎么办 淘宝号码注册过怎么办 农行k宝怎么办信用卡 电脑页面无法显示怎么办 对方银行停止收款怎么办 淘宝东西买太多怎么办 淘宝号黑号了怎么办… 中通包裹异常怎么办 包裹退回去了怎么办 qq支付密码错误怎么办 ie8出现闪退怎么办 平板输不了密码怎么办 华硕笔记本键盘打不开怎么办 电脑打不开rar文件怎么办 苹果手机淘宝卡怎么办 淘宝联盟网址打不开怎么办 淘宝买东西卖家不退货怎么办