ArrayList并发修改异常(forEach遍历,只能删除倒数第二个???)

问题案例分析

public class ArrayListExceptionTest {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        /*for (String s : list) {
            if ("2".equals(s)){
                list.remove(s);
            }
        }*/
          for (String s : list) {
            if ("1".equals(s)){
                list.remove(s);
            }
        }
    }
}

结果1:我们发现删除“1”的时候会报一个并发修改的异常

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
	at java.util.ArrayList$Itr.next(Unknown Source)
	at ArrayListExceptionTest.EqualUnderstand.main(EqualUnderstand.java:38)

结果2:当我们删除“2”的时候,我们发现可以正常删除,却不报错

当我们更换数组里的大小和内容时,我们发现使用ForEach遍历数组时,只能删除倒数第二个,删除其他则报错!!!这是什么原因呢?

ForEach底层使用迭代器进行遍历的,:它会先指针移动来判断是否当前的数组是否有值,再去获取下一个值

下面是伪代码:

  • array:表示遍历的数组
  • hasNext():判断下一个位置是否还有值得方法
  • next():将指针移动到下一个位置,并且返回当前指针所在位置的值
while(array.haxNext(){
   int value = array.next();
}

下面我们来看看遍历的源码:
在这里插入图片描述

如图进行以下解释:
变量:

  • cursor :索引或者指针,表示指向当前遍历元素的位置记录,初始值为0
  • size:记录集合元素的个数
  • modCount:实际修改的次数
  • expectedModCount: 期待修改的次数

方法:

  • checkForComodification: 检查是否出现了并发修改异常(根据modCount != expectedModCount)
  • hasNext: 判断是否有下一个元素,也就是判断是否元素已经遍历完了(根据cursor != size)
  • next:检查是否出现了并发修改异常,cursor变量值+1,获取下一个元素内容

下面我们来看看删除的源码:
在这里插入图片描述

方法:

  • remove:
    查询要删除元素的索引位置
    调用fastRemove方法
  • fastRemove:
    进行索引范围的边界检查
    modCount变量值+1
    进行删除元素位置的迁移拷贝覆盖

所以每次当我们执行删除时执行remove(object)方法,modCount+1
然后再去执行next方法就会导致expectedModCount != ArrayList.this.modCount,抛出并发修改异常

那么为什么删除倒数第二个元素的时候不会报错,让我们看看下面这代码执行流程图的解释:
在这里插入图片描述

我们假设原始的数量为original,实际数量为size
当删除倒数第二个元素的时候,cursor = original -1 size =original - 1
当遍历到最后一个元素的时候,cursor = size,表示遍历结束没有下一个元素

为什么使用iter迭代器删除,却不会报错呢?

案例:

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()){
        String s = iterator.next();
        if ("2".equals(s)){
            iterator.remove();
        }
    }
}

我们发现无论删除什么元素,都是不会报错的!!!!

我们点击remove查看源码:

我发现调用remove方法时,直接赋值修改·expectedModCount = modCount,这样在进行next()检查时,就不会抛出并发修改异常了!!

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值