我从一些教程中了解了这个概念,只要我知道当一个线程正在迭代列表时,其他线程就可以修改底层列表,我们不会得到ConcurrentModificationException( CME ),但是在ArrayList的情况下,我们将得到CME。
但是在下面的程序中,只有一个线程(主线程),但我仍然得到CME ..why?
是因为爱尔兰人吗?
如果我用COWAL替换AL,那么我没有任何异常,但是元素"D“不是well..why吗?
AL<String> l=new AL<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr=l.iterator();
l.add("d");
while(itr.hasNext())
{
String s=itr.next();
Sop(s);
}发布于 2017-12-18 07:42:08
您之所以获得ConcurrentModificationException,是因为ArrayList的迭代器在设计上是失败的,这意味着一旦创建了迭代器,如果ArrayList是修改的(元素的添加或删除),则会抛出ConcurrentModificationException。
如果检查异常日志语句,则会通过itr.next()方法在行itr.next()中抛出异常日志语句,因为迭代器的next()方法通过使用modCount变量调用ArrayList大小的checkForComodification()方法来检查修改。在从列表创建迭代器时,modCount变量会复制该方法。
现在让我们讨论一下CopyOnWriteArrayList,您没有得到这个异常,因为CopyOnWriteArrayList是一个线程安全的变量 of ArrayList,其中所有的可变操作,如add、remove、set,都是通过将内部数组复制到新数组并将旧数组替换为新创建的数组来实现的。
因此,当您从list获得迭代器时,它保存了数组的引用,并且当您向list添加元素时,列表将具有完全新的数组。迭代器仍然指向旧的数组。
您可能已经注意到,新添加的元素by语句l.add("d");没有打印在控制台上。但如果你把整张单子打印出来,它就在那儿了。
下面是您使用CopyOnWriteArrayList的示例代码
List<String> l = new CopyOnWriteArrayList<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr = l.iterator();
l.add("d");
while (itr.hasNext()) {
String s = itr.next();
System.out.println(s);
}
System.out.println(l);生产的产出是:
a
b
c
[a, b, c, d]希望这能有所帮助。享受:)
发布于 2017-12-18 07:07:00
错误是因为行
l.add("d");在创建Iterator之后,您正在修改列表结构(添加或删除元素)。
你打电话的时候
itr.next();在内部,它检查列表中的任何结构更改(在ArrayList中添加或删除),并发现添加了一个元素,因此数组列表的大小发生了变化。所以你才会得到这个例外。
如果在创建Iterator之前或在使用迭代器之后添加该元素,则不会得到此错误。
下面是ArrayList类中next()的代码;
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
......
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}https://stackoverflow.com/questions/47862954
复制相似问题