迭代时将项目添加到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());
}
}
}
如果没有,如何以安全有效的方式实施此行为?
请注意,这不是about a List
,而是具体关于LinkedList
。如果不安全,我会问其他选择。
答案 0 :(得分:5)
不,这不安全。以下代码将抛出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自己的{{ 1}}或
remove
方法,list-iterator将抛出add
。
你想要的是明确使用ListIterator
而不是ConcurrentModificationException
,并使用ListIterator.add
:
Iterator
新元素插入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()
(并忽略返回值)以向后移动光标。