`
itoracja
  • 浏览: 136436 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

为什么会出现 java.util.ConcurrentModificationException 异常?

    博客分类:
  • java
阅读更多
    工作中碰到个concurrentmodificationexception。代码如下:
list list = ...;for(iterator iter = list.iterator(); iter.hasnext();) {    object obj = iter.next();    ...    if(***) {        list.remove(obj);    }}
 <span style="color: #0000ff;"><br></span>在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.concurrentmodificationexception(当然,如果remove的是最后一条,就不会再去执行next()操作了)<br><br>下面来看一下源码
public interface iterator<e> {    boolean hasnext();    e next();    void remove();}public interface collection<e> extends iterable<e> {    ...    iterator<e> iterator();    boolean add(e o);    boolean remove(object o);    ...}
 <br>这里有两个remove方法<br><br>接下来来看看abstractlist
public abstract class abstractlist<e> extends abstractcollection<e> implements list<e> { //abstractcollection和list都继承了collection    protected transient int modcount = 0;    private class itr implements iterator<e> {  //内部类itr        int cursor = 0;        int lastret = -1;        int expectedmodcount = modcount;        public boolean hasnext() {            return cursor != size();        }        public e next() {            checkforcomodification();  //特别注意这个方法            try {                e next = get(cursor);                lastret = cursor++;                return next;            } catch(indexoutofboundsexception e) {                checkforcomodification();                throw new nosuchelementexception();            }        }        public void remove() {            if (lastret == -1)                throw new illegalstateexception();            checkforcomodification();            try {                abstractlist.this.remove(lastret);  //执行remove对象的操作                if (lastret < cursor)                    cursor--;                lastret = -1;                expectedmodcount = modcount;  //重新设置了expectedmodcount的值,避免了concurrentmodificationexception的产生            } catch(indexoutofboundsexception e) {                throw new concurrentmodificationexception();            }        }        final void checkforcomodification() {            if (modcount != expectedmodcount)  //当expectedmodcount和modcount不相等时,就抛出concurrentmodificationexception                throw new concurrentmodificationexception();        }    }   }remove(object o)在arraylist中实现如下:public boolean remove(object o) {    if (o == null) {            for (int index = 0; index < size; index++)        if (elementdata[index] == null) {            fastremove(index);            return true;        }    } else {        for (int index = 0; index < size; index++)            if (o.equals(elementdata[index])) {                fastremove(index);                return true;            }    }    return false;}private void fastremove(int index) {    modcount++;  //只增加了modcount    ....}
 <span style="color: #0000ff;"><br><span style="color: #339966;"><br><strong style="color: #800000;">所以,产生concurrentmodificationexception的原因就是:<br>执行remove(object o)方法之后,modcount和expectedmodcount不相等了。然后当代码执行到next()方法时,判断了checkforcomodification(),发现两个数值不等,就抛出了该exception。<br>要避免这个exception,就应该使用remove()方法。</strong></span><br></span>这里我们就不看add(object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个list了<br><br><br>下面是网上的其他解释,更能从本质上解释原因:<br>iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 iterator 会马上抛出 java.util.concurrentmodificationexception 异常。<br>所以 iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 iterator 本身的方法 remove() 来删除对象, iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
 
1
11
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics