运行以下代码:
@Test
public void test() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
for (String temp : list) {
// 当为A时运行正常,改成B时异常ConcurrentModificationException
if ("B".equals(temp)) {
list.remove(temp);
}
}
}
运行结果:
编译后的Class文件:
@Test
public void test() {
List<String> list = new ArrayList();
list.add("A");
list.add("B");
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String temp = (String)var2.next();
if("B".equals(temp)) {
list.remove(temp);
}
}
}
可以发现源码与编译后的字节码不一样,源码中的“for (String temp : list) {”在真实的字节码中是
“Iterator var2 = list.iterator();
while(var2.hasNext()) {
String temp = (String)var2.next();”
对应的源码:
list.iterator()对应方法的源码:
new Itr()创建对象时,会将modCount值赋值给expectedModCount,而modCount该字段在ArrayList中标识当前对象的修改次数(包括remove和add方法)
add()
remove()
进入while循环时,执行var2.hasNext()方法:
cursor初始化的时候是0,每执行一次next()方法,值自动加1,cursor == size时会跳出循环
当执行next()方法时,首先会执行checkForComodification()方法
查看代码,可以看出当modCount != expectedModCount时,就会抛出ConcurrentModificationException
expectedModCount的值是在创建Itr对象赋值的,而遍历集合的时候,再执行一次remove或add就会导致modCount的值修改,而此时expectedModCount的值未变化,就会报异常ConcurrentModificationException。
如果非要在循环里面remove、add 元素,请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。
ListIterator iterator = list.listIterator();
while (iterator.hasNext()) {
String item = (String) iterator.next();
if("B".equals(item)){
iterator.add("C");
// iterator.remove();
}
System.out.println("改变后的数据:" + list.toString());
}