ConcurrentModificationException(源码学习 Util包 集合)

来源:互联网 发布:arm linux gcc 4.3.2 编辑:程序博客网 时间:2024/06/05 05:50

ArrayList<String> list3=new ArrayList<String>();list3.add("1");list3.add("2");list3.add("3");Iterator i=list3.iterator();//for(Iterator i1=list3.iterator();i1.hasNext();){if(i.hasNext()){String s=(String) i.next();if(s=="1"){list3.remove(s);}}System.out.println(Arrays.toString(list3.toArray()));

上面这样是不不会报错ConcurrentModificationException

但是你用代码中for循环中的代码这种方式遍历就会出错


所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,源码(modCount和expectedModCount)

如下面所示:

 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 remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        modCount++;//在调用此方法的时候modCount的值加1
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // Let gc do its work
    }


下面是AbstractList 实现了 List接口 extends Collections exrends Iterator

public E next() {
            checkForComodification();
   try {
E next = get(cursor);
lastRet = cursor++;
return next;
   } catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
   }
}



final void checkForComodification() {
   if (modCount != expectedModCount){

//因为在调用ArrayList  remove方法的时候modCount 已经加1
throw new ConcurrentModificationException();//异常出现
}
    }
不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用remove()方法。

public void remove() {
   if (lastRet == -1)
throw new IllegalStateException();
            checkForComodification();


   try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
   cursor--;
lastRet = -1;
expectedModCount = modCount;
   } catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
   }
}
这里我们就不看add(Object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个List了


下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

原创粉丝点击