并发修改异常ConcurrentModificationException

一、发生场景:

APP中用户之间相互送礼物之后,会发布事件{事件源就是,送礼人、收礼人[List]、礼物信息},并对其事件进行监听,监听到之后给送礼人以及收礼人进行积分增加的操作。进行断点测试时,很奇怪的是我明明只送给一个用户,但是收礼人会在某一刻由一个变成两个人。这是我打印日志,输出的全部都是两个人。之后我就换了另一种方式,直接循环收礼人,看看到底循环几次,这时在循环完第一次之后直接捕获到:ConcurrentModificationException。

二、认识ConcurrentModificationException:并发修改异常

1.并发修改异常指的是在并发环境下,当方法检测到对象的并发修改,但不允许这种修改时,抛出该异常。
2.当我们对集合进行迭代(遍历)的时候,同时(并发)对集合进行修改,就会产生并发修改
比如说遍历一个集合时,同时对其中一个元素删除,修改等等操作。
3.或者 list 在多线程情况下 既有读又有写,报出ConcurrentModificationException问题,
概括来说分为两种情况
1、一边遍历集合,而另一边在修改集合时,会报ConcurrentModificationException错误
2、在多线程进行插入操作时,由于没有进行同步操作,容易丢失数据,因此会报ConcurrentModificationException错误
具体的细节还要追踪List的源码。

三:分析并捕捉问题:

此时的我是五脸懵,吉德林法则:找到问题的关键,问题便已经解决了一半。那就从头来分析,程序是在什么时候对list进行修改操作的。

首先,多次断点的方式去看收礼人的size是分别有两种情况:1.正常情况.收礼人至始至终都是一个2.不正常情况.收礼人会由1个->2个,两种情况都是偶现,那就对断点很不友好并且还浪费时间。

接着我们把日志也打上,分别在可能操作收礼人的地方打上日志,发现:源事件的收礼人是一个,而进入方法的收礼人却是两个,那就说明在进方法的时候收礼人已经被修改了。问题也很清晰了收礼人应该是在被多个监听事件捕捉到并且其他线程监听到并对收礼人做了修改出现的并发修改。这时突然想到,上一个小活动在做任务的时候,把送礼人加到收礼人的列表中去了,一看代码果然是这样。一下我抽我的心都有了,找到了问题解决就容易多了,创建新的列表来分别添加收礼人和送礼人,问题也就迎刃而解了。

四:总结:

当源事件被多处地方监听的时候,尽量不要在源事件的变量上做改动。

五:建议:分析List源码

如果有时间,还是要看一下List的源码,大致解释一下异常触发地方:

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

modCount :简单理解 就是ArrayList中集合结构的修改次数【实际修改次数】,指的是新增、删除(不包括修改)操作。

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

集合每次新增或删除的时候modCount会自增1,在获取迭代器的时候,集合只会执行一次将实际修改集合的次数modCount的值赋值给预期修改的次数变量expectedModCount,因此迭代期间发现原预期值改变了,就出现了此异常。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值