您的位置:首页 > 编程语言 > Java开发

java.util.ConcurrentModificationException

2012-06-20 22:46 127 查看
前言:这已经不是我碰到的第一个bug了···写了一年多的java了,从一无所知慢慢走过来。觉得让自己成长最快的就是这些时不时出现的错误和bug了。现在觉得很有必要将自己遇见的bug,以及出现的bug的原因好好理解并记录了。不能再以简单的解决bug为要求了。顺便也发布到平台上来和大家交流分享。

java.util.ConcurrentModificationException<=========>我叫它:多线程映射索引同步异常(这个命名只是为了让自己念着能第一时间想起这是什么bug。命名无任何考据,诸位见笑了···)

出现bug的代码片段:

/**对用户容器进行遍历,返回一个没有权限为5的用户对象的容器*/

Iterator<UserPo> t = listU.iterator();

while(t.hasNext()){

UserPo ss = t.next();

if(ss.getPower() == 5){

this.ruv.setTeacher(ss);

listU.remove(ss);

}

}

通过自己收集的资料和网上一起其他的解释,出现这个bug的原因是:Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,(个人理解:也就是上述代码中t对象有一个单链表指向listU对象中的位置,遍历会根据这个表去进行遍历。)Iterator当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象(个人理解:我们这里定义ss后面的list对象叫ss1,ss1后面的叫ss2,ss在listU对象的位置是i。当执行了listU.remove(ss)后,在listU中ss对象被删除,listU容器中i位置现在存放的是ss1,i+1的位置存放的是ss2。当进入下次遍历时,Iterator会根据单链表去i+1的位置找ss1,可是此时的i+1的位置存放的是ss2。这与单链表中的记录不一致,因此才会抛出异常),所以按照
fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。

所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

因此解决上述bug的方法之一是:

Iterator<UserPo> t = listU.iterator();

while(t.hasNext()){

UserPo ss = t.next();

if(ss.getPower() == 5){

this.ruv.setTeacher(ss);

t.remove();

}

}

如果使用增强for循环对listU容器进行遍历,我还没找到办法解决它。这是有同样异常的代码片段:

for(UserPo s:listU){

if(s.getPower() == 5){

this.ruv.setTeacher(s);

listU.remove(s);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: