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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 郑世光 中级黑马   /  2012-8-29 20:22  /  1927 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 郑世光 于 2012-8-29 20:38 编辑

import java.util.*;
class ListDemo
{
public static void main(String[] args)
{
   ArrayList a1=new ArrayList();
   a1.add("java01");
   a1.add("java02");
   a1.add("java03");
   a1.add("java04");
    Iterator it=a1.iterator();
   while(it.hasNext())
  {
   // Object obj=it.next();
    if((it.next()).equals("java02"))
     a1.add("java008");
    sop(it.next());
   }
}
public static void sop (Object obj)
{
  System.out.println(obj);
}
}

上述代码执行没异常,当修改如下时运行时有异常  Exception in thread "main" java.util.ConcurrentModificationException。两部分代码的区别是什么?

import java.util.*;
class ListDemo
{
public static void main(String[] args)
{
   ArrayList a1=new ArrayList();
   a1.add("java01");
   a1.add("java02");
   a1.add("java03");
   a1.add("java04");
   Iterator it=a1.iterator();
   while(it.hasNext())
  {
    Object obj=it.next();        //修改
    if(obj.equals("java02"))    //部
     a1.add("java008");
    sop(obj);                       //分
   }
}
public static void sop (Object obj)
{
  System.out.println(obj);
}
}

3 个回复

倒序浏览
可以先从异常 Exception in thread "main" java.util.ConcurrentModificationException入手,找出问题
通过查阅api知道,当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

例如,某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。


注意,此异常不会始终指出对象已经由不同 线程并发修改。如果单线程发出违反对象协定的方法调用序列,则该对象可能抛出此异常。例如,如果线程使用快速失败迭代器在 collection 上迭代时直接修改该 collection,则迭代器将抛出此异常。

回复 使用道具 举报
曹昌 发表于 2012-8-29 20:37
可以先从异常 Exception in thread "main" java.util.ConcurrentModificationException入手,找出问题
通 ...

上面的两段代码中都有在迭代块中修改Collection,按理说就应该都出现ConcurrentModificationException,为何一个有一个没有呢?
回复 使用道具 举报

这是代码的流程图
上面的函数代码和下面的函数代码都能够编译通过,编译器只检查基本的语法,函数调用在运行时检查吧。
上面的代码运行结果为day02 day04;整个循环过程中没有调用到集合对象al的操作元素的方法add();
所以没有发生ConcurrentModificationException异常;

下面的代码在第二次循环的时候,(it.next()).eauals("java02")条件,满足,所以要调用到集合对象al的操作元素的方法add();
这时虚拟机就会报出异常
ConcurrentModificationException;
这个异常一般发生在集合的操作中,在集合的迭代器中进行集合元素的操作,有两种方法,第一种用迭代器的方法如it.next() ,
调用迭代器的方法去操作集合中的元素,;第二种用集合的方法,如al.add()。
但是如果在迭代器中同时使用两种方法的话(编译时并没有报错),就可能会发生异常,
发生异常的情况是:在迭代器中同时调用到了两种方法的话,也就是你的下面一个代码!
原因是:在进入循环进行操作元素之前,迭代器对象已经通过这句话Iterator it = al.iterator();得到了al集合中的元素信息,
比如说你的代码中,it已经记录了集合中有day01,day02,day03,day04四个元素。
1如果仅仅只是用迭代器的方法来操作集合元素的话,如it.next(),那么迭代器对象it就还会获取al集合的元素信息。
比如al集合中的元素多了,少了,it都知道,这样it继续对集合元素进行操作就不会出错。
2,如果 在使用迭代器中的方法 的同时,你又使用了al对象中操作元素的方法,如al.add(),那么迭代器对象it就不会知道 al.add()所带来的元素信息的变化。
迭代器对象it不知道新添加了哪个元素或删除了哪个元素,这样,在进行以后循环的时候,可能会发生逻辑上错误。
所以jvm要报出异常,希望用户通过代码避免这种情况的发生。
3,所以最好还是在迭代器中只使用迭代器it的方法 来操作元素,这样是绝对安全的。
后面还有其他的迭代器的实现类,提供了更多的方法来帮助用户操作集合对象中的元素。

累死我了......

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马