Java: 在遍历列表时出现ConcurrentModificationException异常

8
当我执行以下代码时,我遇到了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个回答

13

一个同步的列表并不会提供新的Iterator实现,而是使用同步列表的实现。 iterator()实现如下:

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

来自ArrayList:

由该类的迭代器和listIterator方法返回的迭代器是“快速失败”的:如果在迭代器创建后任何时候以任何方式(除了通过迭代器自己的remove或add方法)结构性修改列表,则迭代器都会抛出一个ConcurrentModificationException异常。

来自ConcurrentLinkedQueue#iterator:

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

这两个集合返回的迭代器是设计上不同的。


8

不要做

myCollection.remove(myObject); 

it.remove();

不需要同步或并发集合


我的问题是,它们两者有什么不同? - Vinoth Kumar C M
@cmv,这与你的列表无关。这与你在迭代时尝试修改集合有关。Iterator.remove() 可以让你这样做。 - mre
我的意思是,Collections.synchronizedList不会负责使操作原子化吗..? - Vinoth Kumar C M
@cmv:完全不同的问题。你在这里只有一个线程,所以Collections.synchronizedList实际上并没有起到什么作用。 - Jason S
4
@cmv:是的,但(与异常名所示相反),这不是多个线程同时执行某些操作的问题。这是一个关于单个线程在对列表进行结构性操作(例如添加/删除元素)的同时(即并发地)使用Iterator的问题。除非您通过Iterator本身进行结构性修改,否则该组合是未定义的。 - Joachim Sauer
给@Joachim Sauer点赞,因为他的解释清晰明了。 - sutanu dalui

2
在java.util.concurrent中,ConcurrentLinkedQueue和Collections.synchronizedList有不同的实现方式,因此它们可以选择是抛出ConcurrentModificationException异常还是优雅地处理所描述的情况。显然,ConcurrentLinkedQueue采用了优雅的方式,而由Collections.synchronizedList包装的ArrayList(我猜测这种行为是ArrayList的而不是包装器的)没有这样做。正如@unbeli所说,应该通过迭代器而不是集合本身在迭代时进行删除操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接