ConcurrentModificationException

一,ConcurrentModificationException

Iterator在迭代时,检测(对List内部的modCount进行检测)到并发修改则会快速失败(fail-fast),抛出该异常。值得注意的是,这里指的并发修改并不一定是多线程。单线程情况下也可能抛出该异常。

二,单线程下抛出ConcurrentModificationException

单线程下,以下代码会导致collection快速失败抛出异常:

Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
    Item item = (Item) iterator.next();
    if (item.satisfiesCondition()) {
       collection.remove(item);
    }
}

可以看到,在对collection进行iterate的同时,又对collection进行remove,导致快速失败。那么问题来了,如何在iterate时,保持对collection的正确moidify?

三,在iterate时的正常modify姿势

iterate时,使用iterator自带的remove api,来实现对collection element的删除,如下:

Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
    Item item = (Item) iterator.next();
    if (item.satisfiesCondition()) {
       iterator.remove();
    }
}

如果还想iterate时,往collection中添加element,ArrayList提供了listIterator()方法,来获取改良的ListIterator,他不光提供了remove,还提供了add等方法。

值得注意的是,从源代码来看,iterate的remove或者add,只提供了对单线程并发modify的支持。多线程貌似是不支持的。

四,for

4.1 for Iterator

使用for iterator时,对list进行remove操作也会抛出ConcureentModificationException

    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");

    for (String s : list) {
        if (s.equals("b")) {
            list.remove(s);
        }
    }

4.2 for循环

但是使用for循环则不会出错,如下:

    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.add("d");

    for (int i = 0; i < list.size(); i++) {
        list.remove("b");
    }

严格来说这不算做迭代,它只是通过累加index来达到访问list各元素的目的。这种方式在再次删除元素后,又会使用list.size()来判断list的长度,也既是list的长度是动态变化的。所以如果想删除指定下标的元素,可能会出现意想不到的效果。比如我想删除index 2的元素b,但是由于前面执行了某些删除操作,导致list长度变化,那么index 2目前的内容可能已经不为b了。