在迭代时向LinkedList
添加项是否安全?
class Worker {
final LinkedList<Foo> worklist = new LinkedList<>();
public void work() {
Iterator<Foo> iterator = worklist.iterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
doSomethingWith(foo);
}
}
public void doSomethingWith(Foo foo) {
// do something with foo
// and possibly add one (or more) foo's to the worklist
if (expression) {
worklist.add(new Foo());
}
}
}
如果没有,如何以安全有效的方式实现此行为?
注意,这不是关于List
,而是关于LinkedList
。
不,不安全。下面的代码将抛出一个ConcurrentModificationException
:
final LinkedList<Foo> worklist = new LinkedList<>();
worklist.add(new Foo());
Iterator<Foo> iterator = worklist.iterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
worklist.add(new Foo());
}
LinkedList
不覆盖iterator()
, AbstractSequentialList
中定义的默认实现是调用listIterator()
, LinkedList
覆盖listIterator
。
引用LinkedList.listIterator
的文档:
list- Iterator fail-fast:如果在Iterator创建后的任何时间,以除通过list- Iterator自己的
remove
或add
方法之外的任何方式修改了list- Iterator,则list- Iterator将抛出ConcurrentModificationException
。
你想要的是显式地使用ListIterator
,而不是Iterator
,并使用ListIterator.add
:
final LinkedList<Foo> worklist = new LinkedList<>();
worklist.add(new Foo());
ListIterator<Foo> iterator = worklist.listIterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
iterator.add(new Foo());
}
新元素被插入到next()
返回的元素之前,因此对next()
的后续调用不受影响。如果您想将新项添加到迭代中,您可以在添加元素后调用previous()
(并忽略返回值)来向后移动光标。