Java:迭代列表时出现ConcurrentModificationException

时间:2011-07-06 12:53:30

标签: java collections

当我执行以下代码时,我得到ConcurrentModificationException

 Collection<String> myCollection = Collections.synchronizedList(new ArrayList<String>(10));
    myCollection.add("123");
    myCollection.add("456");
    myCollection.add("789");
    for (Iterator it = myCollection.iterator(); it.hasNext();) {
        String myObject = (String)it.next();
        System.out.println(myObject);
        myCollection.remove(myObject); 
        //it.remove();
    }

为什么我得到异常,即使我使用的是Collections.synchronizedList?

当我将myCollection更改为

  ConcurrentLinkedQueue<String> myCollection = new ConcurrentLinkedQueue<String>();

我没有得到那个例外。

java.util.concurrent中的ConcurrentLinkedQueue与Collections.synchronizedList有何不同?

3 个答案:

答案 0 :(得分:13)

synchronized 列表不会提供Iterator的新实现。它将使用 synchronized 列表的实现。 iterator()的{​​{3}}是:

public Iterator<E> iterator() {
   return c.iterator(); // Must be manually synched by user! 
}

来自ArrayList

  

此类的iterator和listIterator方法返回的迭代器是 fail-fast :如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的remove或添加方法,迭代器将抛出ConcurrentModificationException

来自ConcurrentLinkedQueue#iterator

  

以适当的顺序返回此队列中元素的迭代器。返回的迭代器是一个“弱一致”迭代器,永远不会抛出ConcurrentModificationException,并保证遍历构造迭代器时存在的元素,并且可能(但不保证)反映施工后的任何修改。

两个集合返回的迭代器设计不同

答案 1 :(得分:7)

不要做

myCollection.remove(myObject); 

it.remove();

无需同步或并发收集

答案 2 :(得分:2)

  

java.util.concurrent中的ConcurrentLinkedQueue与Collections.synchronizedList有何不同?

它们具有不同的实现,因此可以选择是抛出ConcurrentModificationException,还是处理您优雅描述的情况。显然CLQ处理得很好,并且由Collections.synchronizedList包装的ArrayList(我的猜测是行为是ArrayList的,而不是包装器的)不会。

正如@unbeli所说,通过迭代器删除,而不是迭代时的集合。