arraylist 并发_阿里开发手册之ArrayList正确操作方式

点击上方“码邦主”,关注公众号,免费获取Java电子书,面试题 

[强制]不要在foreach循环里进行元素的remove/add操作。remove 元索请使用 Iterator方式,如果并发操作,需要对Iterator对象加锁。

正例:
ist<String> list = new ArrayList<>0;
list,add("1); listadd(C2";
Iterator<String> iterator = listiterator0);
while (iterator. hasNext0) I
String item = iterator.next0;
if (删除元素的条件) {
iterator.remove0;
}
}
反例:
for (String item : list) 1
if (C1'equals(tem) (
listremovelitem);
}
}

说明:以上代码的执行结果肯定会出乎大家的意料,那么试一下把"1"换成*2”, 会是同样的结果吗?

运行结果如下

b27e1deeb871fce2f7fdc9f41f68001d.png

看似没有语法错误,那报错的原因是什么?该怎么改呢?

首先咱们把当前代码编译后的字节码文件反编译看看

4dc8d98cbd5dfadf84050fc5e7907db8.png

可以看到上面我们写的foreach被转成了迭代器,在24行删除的时候是用的ArrayList的remove方法。接下来再看ArrayList源码,在看源码前要了解一个知识点,ArrayList是继承了AbstractList。

6468ad1b8102ab6b627e56351d7d19e0.png

在AbstractList中有一个变量modCount

1a5f99a78eb36a3c0b36ceb578f2d40a.png

这个变量的作用是统计ArrayList操作的次数,比如添加删除都会加一的。接下来再看ArrayList中的remove方法

4da291f599f4d98dfa9475e8992c0bcc.png

在这里当要删除的元素在数组中找到了以后,就调用fastRemove方法,接下来再看看fastRemove方法

ae7ba151bb1f6e6c3ba2df4357c3cd03.png

在这里可以看到对于modCount进行了++操作。再回过头来看我们写代码的反编译代码

c9372840fdf9bcc3841d41c088f10985.png

执行了ArrayList中的remove方法,所以会执行++this.modCount;

执行完remove(var3)以后会再执行hashNext和执行(String)var2.next();那咱们再看看迭代器及他的next方法

845f1cd62422bbc2cf4540aa6c4fa6ac.png

在迭代器中有一个expectedModCount;代表对 ArrayList 修改次数的期望值,把ArrayList中的modCount赋值给了他,证明初始值就是ArrayList中的modCount。

然后在执行next方法的时候会首先调用checkForComodification方法,如上图660行,咱们再来看checkForComodification方法

7f497a1418219c16c884195e0eb7f154.png

在这里判断了ArrayList中的操作次数modCount和期望操作次数。问题其实就在这里,当我们调用了remove以后modCount就会执行++,加一操作,但是expectedModCount还是最开始获取迭代器的时候把之前的modCount赋值给expectedModCount的,所以这个时候两个数是不相等的,会抛出异常ConcurrentModificationException。如何规避这个问题呢,可以用迭代器中的remove方法,看迭代器中的remove源码

a553f764dc62d3e382c4e034c4dc80fb.png

在迭代器中的每次删除数据的时候都会把modCount赋值给expectedModCount,这样在判断的时候就肯定是相等的了。如下图

6a4e03a2c8f4248bf35194c0be815ebd.png

如有不详的地方,欢迎评论区讨论

欢迎关注,转发朋友圈噢

 

f239f7983752ee264dee6edaba3f2a4c.png

你“在看”我吗?

8afef225ab8adef75c7543637fddf7c4.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值