Java中ConcurrentModificationException异常分析与解决方案

127 阅读2分钟

背景: 项目代码中有将获取到的数据存储到List中,然后遍历List处理数据,当遍历过程中再此修改这个List就会报ConcurrentModificationException异常。

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

    • 异常原因分析:

      异常抛出在ArrayList类中的checkForComodification()方法中。下面是checkForComodification方法的源码:

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

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

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

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

      •  

      • 经过上面的分析,我们知道了当我们获取到集合的迭代器之后,Itr对象创建成功后,expectedModCount 的值就确定了,就是modCount的值,在迭代期间不允许改变了。要了解它两为啥不相等, 我们就需要观察ArrayList集合的什么操作会导致modCount变量发生变化,从而导致modCount != expectedModCount ,从而发生并发修改异常。

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

      • add():每添加一个元素,modCount的值也会自增一次

      • remove():每删除一个元素,modCount的值会自增一次

      • **
        **

      • 如何避免并发修改异常?

        如何避免并发修改异常还有它的特殊情况呢,其实Iterator迭代器里面已经提供了remove(),用于在迭代过程对集合结构进行修改,使用iterator.remove()不会产生并发修改异常。