我从一些教程中理解了这个概念,只要我知道一个线程何时迭代列表,就允许其他线程修改底层列表,我们不会得到 ConcurrentModificationException(CME),但在 ArrayList 的情况下,我们将得到 CME。
但在下面的程序中只有一个线程(主线程),但我仍然得到 CME ..为什么?
是因为迭代器吗?
如果我用 COWAL 替换 AL ,那么我不会得到任何异常,但我也没有元素“D”..为什么?
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);
}
最佳答案
您将收到 ConcurrentModificationException
,因为 ArrayList
的迭代器在设计上是快速失败。这意味着,一旦创建了迭代器,如果ArrayList
被修改(添加或删除元素),它将抛出ConcurrentModificationException
。
如果您检查异常日志语句,它会被 itr.next()
方法在 String s=itr.next();
行抛出,因为 迭代器的 next()
方法通过使用其复制的 modCount
变量调用 checkForCommodification()
方法检查 ArrayList
大小的修改情况从列表创建迭代器时。
现在让我们谈谈 CopyOnWriteArrayList
,您没有收到此异常的原因是 CopyOnWriteArrayList
是 的线程安全变体 ArrayList
,其中所有可变操作(如添加、删除、设置)都是通过将内部数组复制到新数组并用新创建的数组替换旧数组来实现的。
因此,当您从列表中获取迭代器时,它会保存数组的引用,并且当您向列表添加元素时,列表将拥有全新的数组。并且迭代器仍然指向旧数组。
您可能已经注意到,通过语句 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]
希望这有帮助。 享受吧:)
关于java - CopyOnWriteArrayList(cowal),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47862954/