多线程下使用List中的subList和remove方法产生的 java.util.ConcurrentModificationException 异常

在说多线程操作List之前,我们先看下单线程下产生的问题:

单线程

List<Integer> listA=new ArrayList<>();
listA.add(1);
listA.add(2);
listA.add(3);
listA.add(4);
listA.add(5);
listA.add(6);


for(Integer a:listA){
  if (a==3) {
    listA.remove(3);
  }
}

//再次使用集合就会报错

System.out.println("list元素:" + listA);

该段代码最终会抛出  java.util.ConcurrentModificationException 错误,主要的原因是:

在List循环时,会初始化modCount=0;当该集合进行增加、删除操作值,modCount会自增;而我们使用加强for循环时候,会把modCount初始化的值给迭代器中的expectedModCount,也就是说开始expectedModCount也是为0;但是当集合操作了新增元素,modCount++ ,但是expectedModCount没有新增。导致modCount和expectedModCount不一致,当我们再次访问这个原集合时候,就会抛出java.util.ConcurrentModificationException 错误。

多线程

 说明:subList 返回的是 ArrayList 的内部类 SubList,并不是ArrayList ,而是 ArrayList 的一个视图,对于SubList子列表的所有操作最终会反映到原列表上,对SubList操作,其实也是对ArrayList 操作,比如删除SubList中的元素,同时也会删除ArrayList 的元素。 在subList场景中,高度注意对父集合元素的增加或删除,均会导致子列表的遍历、增加、删除产生 ConcurrentModificationException 异常。

List<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        arrayList.add(5);
        arrayList.add(6);


        Thread t1= new Thread(new Runnable() {
            @Override
            public void run() {
                List<Integer> list = arrayList.subList(0, 3);
                for (Integer integer : list) {
                    System.out.println(" "+integer);
                    if(integer == 2){
                        list.remove(integer);
                    }
                }
                System.out.println("进行元素的删除操作");
                //arrayList.remove(4);
                System.out.println("list元素:" + list);
            }
        });
        Thread t2= new Thread(new Runnable() {
            @Override
            public void run() {
                List<Integer> list2 = arrayList.subList(4, 6);
                for (Integer integer : list2) {
                    System.out.println(" "+integer);
                    if(integer == 4){
                        list2.remove(integer);
                    }
                }
                System.out.println("进行元素的删除操作");
                //arrayList.remove(4);
                System.out.println("list元素:" + list2);
            }
        });
        t1.start();
        t2.start();

 

ArrayList中有个protected transient int modCount = 0; 用来记录当前ArrayList被修改的次数。

比如add(),remove()等都会导致modeCount增加: ArrayList.subList()会生成一个SubList的对象,SubList中有个对应modCount同步ArrayList中的modeCount: SubList对象每次再遍历时,会将自己的modeCount与ArrayList的modeCount进行对比,如果两个值不一样就会报异常:ConcurrentModificationException

posted @ 2024-05-17 14:18  牧码人hhom  阅读(5)  评论(0编辑  收藏  举报