ConcurrentModificationException是遍历过程中修改list而抛出的错误。就像前面分析的,单线程时这种错误主要是因为使用forEach造成:遍历一个拷贝,修改原始list,造成的。简单的大家都知道,这里要说一种比较隐蔽的出错方式:

 1 public class ExceptionTest{
2
3 private List<String> list = new ArrayList<>();
4
5 public ExceptionTest(){
6 for(int i=0;i<9;i++){
7 list.add("string"+i);
8 }
9 }
10
11 public void throwExceptions(){
12 List<List<String>> listList = new ArrayList<>();
13 listList.add(list.subList(0,3));
14 listList.add(list.subList(3,6));
15 listList.add(list.subList(6,8));
16 Iterator<List<String>> it1 = listList.iterator();
17 while(it1.hasNext()){
18 List<String> l = it1.next();
19 Iterator<String> it = l.iterator();
20 while(it.hasNext()){
21 String str = it.next();
22 if(str.endsWith(("5"))){
23 it.remove();
24 }
25 }
26 }
27 }
28 }

运行上面的代码还是会出错,虽然两层循环都用来Iterator。如果不仔细看很难发现这其中的原因。当你调试你会发现,删除以5结尾的字符串的时候,listList中的第一个子list会报错,而不是正在做修改的第二个子list。所以这个错误的来源不是两个遍历的本事,而是listList的初始化方式,可以看到13到16行,每个子列表使用的是list的subList方法。进一步查看subList代码可以发现。这个方法其实并未新建list而是返回了原理list的一个视图(其实索引):

SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}

所以在修改第二个子list的时候回引起父列表(list)状态发生改变,虽然两层遍历看起来是正常的,但是他们却是在遍历和修改同一个list,因此会抛出ConcurrentModificationException异常。

总结:有时候的异常并不是因为当前的步骤引起的,原因有可能来自于之前的某一步骤。

一种较为隐蔽ConcurrentModificationException情形的更多相关文章

  1. [转]Javascript中几种较为流行的继承方式

    出处:http://www.jianshu.com/p/a6c005228a75 开篇 从'严格'意义上说,javascript并不是一门真正的面向对象语言.这种说法原因一般都是觉得javascrip ...

  2. auto_ptr解析

    auto_ptr是当前C++标准库中提供的一种智能指针,或许相对于boost库提供的一系列眼花缭乱的智能指针, 或许相对于Loki中那个无所不包的智能指针,这个不怎么智能的智能指针难免会黯然失色.诚然 ...

  3. c++11 auto_ptr介绍

    在代码里面看到了auto_ptr这个东西,正好以前一哥们曾经问过我这个问题..所以特意去搜了搜帖子,学习学习 http://www.cnblogs.com/gaoxianzhi/p/4451803.h ...

  4. auto_ptr, which can release the space automatically

    C++的auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理. 使用std::auto_ptr,要#include <memory>.[1]  中文名 自动指针 外 ...

  5. c++智能指针《一》 auto_ptr

    转载http://www.cnblogs.com/gnagwang/archive/2010/11/19/1881811.html C++的auto_ptr auto_ptr所做的事情,就是动态分配对 ...

  6. C++智能指针--auto_ptr指针

    auto_ptr是C++标准库提供的类模板,头文件<memory>,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同一时候被分给两个拥有者.当 ...

  7. .NET中的缓存

    构建高性能的应用程序的非常重要一项就是使用缓存.使用缓存可以避免重新从读取服务器端读取数据,节省数据从客户端到服务器间往返的时间,同时也减轻了服务器数据存取的压力.如果客户端非常频繁地读取服务器上的数 ...

  8. 测试MySQL锁的问题

    测试MySQL锁的问题 目录 测试MySQL锁的问题 1 Record Lock 2 Next-Key Lock 2 死锁测试 InnoDB支持三种行锁: Record Lock:单个行记录上面的锁 ...

  9. PostgreSQL EXPLAIN执行计划学习--多表连接几种Join方式比较

    转了一部分.稍后再修改. 三种多表Join的算法: 一. NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...

随机推荐

  1. BZOJ 4144 Dijkstra+Kruskal+倍增LCA

    思路: 先把所有的加油站 push进按weight排序的优先队列里 对于每个不是加油站的点 找到到它的点的最短路以及它来源的加油站 如果x和y有边 且x和y加油站的来源不一样 则它可以连边 跑一边Kr ...

  2. HBase的单节点集群详细启动步骤(分为Zookeeper自带还是外装)

    伪分布模式下,如(weekend110)hbase-env.sh配置文档中的HBASE_MANAGES_ZK的默认值是true,它表示HBase使用自身自带的Zookeeper实例.但是,该实例只能为 ...

  3. P2617 Dynamic Ranking

    题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤ ...

  4. 关于servlet的web.xml映射

    1.原理 <servlet> <!-- servlet的名字,随便起个名,但和下面的servlet名一致 --> <servlet-name>hello</s ...

  5. 机器学习实践:《Python机器学习实践指南》中文PDF+英文PDF+代码

    机器学习是近年来渐趋热门的一个领域,同时Python 语言经过一段时间的发展也已逐渐成为主流的编程语言之一.<Python机器学习实践指南>结合了机器学习和Python 语言两个热门的领域 ...

  6. 学习“花书“《深度学习》中文PDF和英文PDF

    个人觉得github上的中文版翻译的不错,有700多页,深度学习入门经典书籍,前几章的数学基础介绍的相当不错. 第一部分基本就是统计学习最基础的线性代数,概率论等,第4章值得一读,讲了些数值分析里常涉 ...

  7. js编码方式详解

    escape.encodeURI 和encodeURIComponent 的区别 escape(), encodeURI()和encodeURIComponent()是在Javascript中用于编码 ...

  8. GPU和CPU的区别

    http://blog.csdn.net/conowen/article/details/7256260 这里有几种计算平台的Flynn分类法 GPU是SIMD 多核CPU是MIMD 硬件结果多核处理 ...

  9. Spring : 征服数据库(一)

    严格的说.这里征服的是关系型数据库.之后笔者会以MongoDB为例,给出非关系型数据库的解决方式,敬请期待. 获取连接,操作,关闭,不知所云的异常...是的,你受够了.在使用纯JDBC时你訪问数据库时 ...

  10. 在resin配置參数实现JConsole远程监控JVM

    在Resin配置參数实现JConsole远程监控JVM 在Resin中配置中配置下列參数,就能够是实现了! <jvm-arg>-Dcom.sun.management.jmxremote& ...