一、案例
//案例一
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
} //运行不报错
//案例二
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
for (String item : list) {
if ("2".equals(item)) {
list.remove(item);
}
}
} //运行报错Exception in thread "main" java.util.ConcurrentModificationException
二、javap反编译后字节码分析
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #2 // class java/util/ArrayList
3: dup
4: invokespecial #3 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: ldc #4 // String 1
11: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
16: pop
17: aload_1
18: ldc #6 // String 2
20: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
25: pop
26: aload_1
27: invokeinterface #7, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
32: astore_2
33: aload_2
34: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
39: ifeq 72
42: aload_2
43: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
48: checkcast #10 // class java/lang/String
51: astore_3
52: ldc #6 // String 2
54: aload_3
55: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
58: ifeq 69
61: aload_1
62: aload_3
63: invokeinterface #12, 2 // InterfaceMethod java/util/List.remove:(Ljava/lang/Object;)Z
68: pop
69: goto 33
72: return
21-25行:java编译器把for循环编译成List.iterator,然后通过Iterator.hasNext,Iterator.next遍历,然后checkcast指令String类型校验
三、源码分析
- 调用ArrayList.iterator(),返回Iterator对象
- 标记5是Iterator对象的remove(),标记6是ArrayList的remove()
- cursor是Iterator当前指针,lastRet是Iterator上次遍历的指针,modCount是ArrayList的变更次数,当add(1),add(2),remove(1)时,modCount=3
案例一分析:
- add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
- Iterator.hasNext():返回true
- Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
- equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=1,size=1
- Iterator.hasNext():返回false,退出循环
总结:根本就没有遍历第二个字符串“2”
案例二分析:
- add(1),add(2),for遍历 : modCount=2,expectedModCount=2,cursor=0,size=2
- Iterator.hasNext():返回true
- Iterator.next():标记3的checkForComodification()校验成功,返回字符串“1”
- equals=false:modCount=2,expectedModCount=2,cursor=1,size=2
- Iterator.hasNext():返回true
- Iterator.next():标记3的checkForComodification()校验成功,返回字符串“2”
- equals=true,调用标记6的ArrayList的remove():modCount=3,expectedModCount=2,cursor=2,size=1
- Iterator.hasNext():返回true
- Iterator.next():标记3的checkForComodification()校验失败,modCount != expectedModCount抛异常ConcurrentModificationException
总结
1. ArrayList.remove()方法不会更新expectedModCount,cursor,只更改了原数组,size,modCount等数据,由于数据不一致导致校验失败。
2. Iterator.remove()方法会更新原数组,size,modCount等数据。