并发修改异常 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()方法,就不会发生并发修改异常。
小结论:
- 迭代器调用remove()方法删除元素,底层还是调用的集合的删除元素的方法;
- 在调用remove()方法后,都会将modCount的值赋值给expectedModCount,保证了它两的值永远都是相等的,所以也就不会产生并发修改异常;