遍历集合ConcurrentModificationException异常

来源:互联网 发布:ipad看片用什么软件 编辑:程序博客网 时间:2024/06/08 06:59

在遍历集合时,如果进行了增删操作,有时会抛出 java.util.ConcurrentModificationException异常。这类异常也被称为 fail-fast,它是Java集合的一种错误检测机制。

出现异常的原因:使用了iterator和foreach(底层也是使用了iterator的方式)进行遍历,并且遍历期间进行add或remove操作,那就有可能发生此异常。出现异常的关键就在于iterator的next()方法,下面是其源码

    public E next() {        checkForComodification();        try {            E next = get(cursor);            lastRet = cursor++;            return next;         } catch (IndexOutOfBoundsException e) {            checkForComodification();            throw new NoSuchElementException();        }    }
其中的checkForComodification()方法会检查集合的大小,如何跟预期的,也就是与list.iterator()调用时的集合大小不一致,就是抛异常。

单线程下的解决方法

        // 使用最原始的下标遍历方式        for ( int i = 0; i < myList.size(); i++) {            String value = myList.get(i);            if (value.equals( "3")) {                myList.remove(value); // ok                i--; // 因为位置发生改变,所以必须修改i的位置            }        }        // 使用iterator的remove方法,而不使用集合本身的remove方法        for (Iterator<string> it = myList.iterator(); it.hasNext();) {            String value = it.next();            if (value.equals( "3")) {                it.remove(); // ok            }        }        // 把需要删除的元素添加到临时集合中,遍历结束后使用removeAll方法删除        List<string> templist = new ArrayList<string>();        for (String value : myList) {            if (value.equals( "3")) {                templist.remove(value); }            }        }        myList.removeAll(templist);
多线程下的解决方法
尽量使用java.util.concurrent包下的集合,不推荐使用synchronizer来加锁或者使用Collections.synchronizedList,效率比较慢,会导致多个线程遍历时阻塞。推荐使用CopyOnWriteArrayList,对于map,在多线程情况下,也推荐使用ConcurrentHashMap。

    List<string> myList = new CopyOnWriteArrayList<string>();    myList.add("a");    myList.add("b");    myList.add("c");    for (int i = 0; i < myList.size(); i++) {        String value = myList.get(i);        if (value.equals( "3")) {            myList.remove(value);            i--; // 记得下标减1,使得下次遍历能遍历到删除元素的下个元素,否则会跳过该元素        }     }


阅读全文
0 0