当我们在当前节点之后添加某个对象或在当前节点之后删除某个对象时,Iterator
如何抛出ConcurrentModificationException
。 Iterator
是否保留对基础集合的副本或引用?
答案 0 :(得分:5)
迭代器维护对底层集合的引用。如果你添加或删除一个元素,迭代器可能会留在一个不可能的索引,或者集合可能会从迭代器的“下面”改变。
因此,在不让你知道的情况下,不要让迭代器被破坏,大多数集合都会在你尝试在迭代时修改集合时抛出ConcurrentModificationException,这样你就不会遇到不可预测的损坏的迭代器。
答案 1 :(得分:2)
按合同规定,在迭代时不允许修改集合(除非使用Iterator.remove()
等)。
当你执行此操作时,该集合不是随机失败,而是足以跟踪它被修改的次数,并在检测到并发修改时抛出ConcurrentModificationException
。
答案 2 :(得分:1)
ConcurrentModificationException可能是你的朋友,你应该学会忍受它。但是,只是为了完整性:
有非Oracle集合,不会抛出ConcurrentModificationException。它们更快(因为它们不花时间检查),而且显然更灵活,但在使用时需要更加小心。
Oracle有四个(最后计数)“并发”类,它们不会在java.util.concurrent(ConcurrentHashMap,ConcurrentLinkedQueue,ConcurrentSkipListMap和ConcurrentSkipListSet)中抛出它。它们比非并发等价物略慢,但它们是线程安全的和它们不会阻塞。无论你做了什么,他们都不会加扰你的数据,但他们不会阻止你加扰它。
答案 3 :(得分:1)
要删除,可以使用iterator.remove(),如下所示:
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Object object = iterator.next();
/* ... */
if (condition) {
iterator.remove();
}
对于添加,您可以替换ListIterator的简单Iterator,如下所示
ListIterator<Object> iterator = list.listIterator();
iterator.add(new Object());
答案 4 :(得分:0)
当然,迭代器有一个指向底层集合的链接,这可以避免复制。如果您在ArrayList迭代器(ListItr)的源代码中查找示例,您将看到它主要具有指向列表和游标的链接。
因此,不要在线程之间共享迭代器,也不要修改要迭代的集合。