共计 1074 个字符,预计需要花费 3 分钟才能阅读完成。
一、应用背景
在阿里巴巴开发手册中,有这样一条规定:不要在 foreach 循环里进行 add 和 remove 操作(这里指的是 List 的 add 和 remove 操作),否则会抛出 ConcurrentModificationException。remove 元素请应用 iterator。
二、源码
1. 咱们晓得 foreach 是语法糖,他实质还是 iterator 进行的循环,因而上面的代码和应用 foreach 循环是一样的。在循环外面咱们应用“谬误”操作,应用 List 的 add 办法进行操作,会抛出 ConcurrentModificationException
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("apple");
Iterator<String> iterator = arrayList.iterator();
while(iterator.hasNext()){String value = iterator.next();
if("apple".equals(value)){arrayList.add("orange");
}
}
三、源码解析
1.arrayList.iterator();
①返回 Itr 类,并将 modcount 的值赋值给一个变量 expectedModCount,其中 modcount 示意 List 理论被增删的次数,expectedModCount 示意该迭代器冀望被增删的次数,当新建 Itr 类的时候会给他赋初始值,只有通过该迭代器进行值的增删才会批改该值
2.iterator.next();
①在调用迭代器的 next 办法时,他会进行查看,比拟 modCount 和 expectedModCount 的值,如果不相等,Concurrent
四、总结
1.modCount 和 expectedModeCount 不统一才会抛出 ConcurrentModificationException。当咱们调用 List 的 remove 办法时,他只会批改 modCount 的值;当咱们调用 iterator 的 remove 办法,他会将 modCount 的值赋值给 expectedModeCount
2.modCount 和 expectedModeCount 是属于 fast-fail 机制,用于多线程中,当进行遍历的时候,有其余线程批改值的时候就会进行查看
五、解决办法
1. 应用一般 for 循环进行操作
2. 在循环中应用 iterator 进行操作
3. 应用 stream 流进行过滤
4. 应用 fast-saft 平安的类,如 ConCurrentLinkedQueue
正文完