A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王金科 中级黑马   /  2012-9-1 03:07  /  2438 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 王金科 于 2012-9-1 13:19 编辑
  1. List<String> list = new ArrayList<String>();
  2.                
  3.                 list.add("a");
  4.                 list.add("b");
  5.                 list.add("c");
  6.                 list.add("d");
  7.                 list.add("e");
  8.                 list.add("f");
  9.                
  10.                
  11.                List list2 = list.subList(1, 4);
  12.                System.out.println(list2);//放在这里就不会出问题
  13.                
  14.                list.clear();
  15.                
  16.                System.out.println(list);
  17.                
  18.                System.out.println(list2);//这句放这里为什么不行啊,运行就抛异常java.util.ConcurrentModificationException
复制代码

评分

参与人数 1技术分 +1 收起 理由
包晗 + 1

查看全部评分

7 个回复

倒序浏览
发生这个异常的根本原因是改变列表数据结构而引发ConcurrentModificationException异常。这段代码与下面代码同理,都 会抛出并发修改异常。
  1. List<String> list = new ArrayList<String>();
  2.                 list.add("a");
  3.                 list.add("b");
  4.                 list.add("c");
  5.                 list.add("d");
  6.                 list.add("e");
  7.                 list.add("f");
  8.                 list.clear();
  9.                 System.out.println(list);
  10.                 List list2 = list.subList(1, 4);
  11.                 System.out.println(list2);
  12.                 System.out.println(list2);// 上面的代码等同于这样
复制代码
我查API找到如下说明:
在subList这个方法上有明确的说明(“返回的列表由此列表支持,因此返回列表中的非结构性更改将反映在此列表中,反之亦然。返回的列表支持此列表支持的所有可选列表操作。”),而它操作的是List中的一段。
这是异常抛出的原因:“如果支持列表(即此列表)通过任何其他方式(而不是通过返回的列表)从结构上修改,则此方法返回的列表语义将变为未定义(从结构上修改是指更改列表的大小,或者以其他方式打乱列表,使正在进行的迭代产生错误的结果)”。
这个为异常类的说明 :“此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常”。

评分

参与人数 1技术分 +1 收起 理由
包晗 + 1

查看全部评分

回复 使用道具 举报
很明显,这是并发修改异常
问题就在下边这几条语句:
  1. list.clear();
  2. System.out.println(list);
  3. System.out.println(list2);//这句放这里为什么不行啊,运行就抛异常java.util.ConcurrentModificationException
复制代码
在前边已经定义了List list2 = list.subList(1, 4),而现在对list进行了修改,由于list2是通过list而来的(是list的子集合),
所以当你修改list的时候list2的值就已经改变了。
这就会出现让虚拟机不知道你要打印的list2的值是什么的情况。就会抛出并发修改异常。
主意subList()方法中有这么一句说明:如果支持列表(即此列表)通过任何其他方式(而不是通过返回的列表)从结构上修改,则此方法返回的列表语义将变为未定义(从结构上修改是指更改列表的大小,或者以其他方式打乱列表,使正在进行的迭代产生错误的结果)。
这就是要抛出异常的原因。

评分

参与人数 1技术分 +1 收起 理由
包晗 + 1

查看全部评分

回复 使用道具 举报
List list2 = list.subList(1, 4);
list.clear();
System.out.println(list);
System.out.println(list2);//这里打印list2的时候,因为list已经发生了改变,而list2是list的子集合,有2条语句在操作同一个集合,虚拟机不知道所要打印的list2是什么情况,所以就出现了并发修改异常。

评分

参与人数 1技术分 +1 收起 理由
包晗 + 1

查看全部评分

回复 使用道具 举报
芦曦 发表于 2012-9-1 09:46
List list2 = list.subList(1, 4);
list.clear();
System.out.println(list);

我的想法是这样的,
List list2 = list.subList(1, 4);这个返回的是一个视图,只是有一个映射关系,列表list2里面实际上是没有数据
当list被清空时,映射关系就不存在了,所以后面要打印list2时,虚拟机就不知道了
这样的恰当不恰当??
回复 使用道具 举报
很简单啊,subList(int fromIndex, int toIndex)方法返回的子列表对象中从fromIndex到toIndex - 1的范围内的元素,与父列表中从fromIndex到toIndex - 1的范围内的元素是相同的元素,是同一块内存中存放的元素,所以对子列表的修改会反映在父列表身上,反之亦然.所以当你调用父列表的clear()方法删除父列表的所有元素后,也会反应在子列表身上,也就是说此时子列表的所有元素都没有了.父列表的所有元素没有了,子列表自然不会再有任何元素了,因为子列表的元素就是引用的父列表中的元素.
回复 使用道具 举报
list=[a,b,c,d,e,f]
list2是由list的sublist而来的,因此,jvm不会开辟新的空间来存放list2,只会对list存一个引用关系。而ConcurrentModificationException异常:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。也说明了list与list2引用的是一个内容。
回复 使用道具 举报
王金科 发表于 2012-9-1 11:28
我的想法是这样的,
List list2 = list.subList(1, 4);这个返回的是一个视图,只是有一个映射关系,列表list2 ...

这样理解确实是说的过去,应该没错.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马