记录一个ConcurrentModificationException
代码如下:
package com.cc; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ExceptionTest { public static void main(String[] args) { Map<String, Object> map = new HashMap<String, Object>(); List<String> list = new ArrayList<String>(); for (int i = 0; i < 10; i++) { list.add(i + ""); } map.put("test", list.subList(0, 3)); list.add(""); List<String> listTest = (List<String>) map.get("test"); System.out.println(listTest.get(0)); } }
异常信息:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231) at java.util.ArrayList$SubList.get(ArrayList.java:1035) at com.cc.ExceptionTest.main(ExceptionTest.java:20)
原因分析:
我们知道subList生成的子列表只是原列表的一个视图而已,如果我们操作子列表它产生的作用都会在原列表上面表现,但是如果我们操作原列表会产生这种情况情况!
JDK有这么一段注释:迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
“快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。
结论:
对于子列表视图,它是动态生成的,生成之后就不要操作原列表了,否则必然都导致视图的不稳定而抛出异常。
有时间要翻出Arraylist源码再复习一下了
如有理解不当或建议,欢迎指正
作者:不放糖的咖啡
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.