问题描述
我定义了一个 ConcurrentLinedQueue 并像这样循环:
ConcurrentLinkedQueue clq
.forEach((carTask -> {
现在,如果我从队列中删除 carTask。这是一个元素
在我们执行 forEach 时在队列中会导致任何问题吗?
我想到的一种选择是将要删除的元素
在一个单独的列表中,一旦 forEach 结束,只需删除所有
从列表中获取队列中的元素。
我不确定这种替代方法是否能完美运行
有什么建议或更好的方法来解决这个问题吗?
解决方法
这个特定的例子不会导致错误,因为 Queue
的这个实现允许并发修改。
但是通过 remove
方法从 Java 集合中删除元素,当您在元素上循环时,通常会导致 ConcurrentModificationException
。相反,使用 Iterator
并调用其 remove
方法是一个好习惯:
Collection<String> c = new LinkedList<>();
c.add("foo");
c.add("bar");
for(Iterator<String> it = c.iterator(); it.hasNext(); ) {
String s = it.next();
if(s.equals("foo")) {
it.remove();
}
}
// collection now contains only "bar"
除了防止 ConcurrentModificationException
之外,这是更可取的,因为 remove
对于许多集合的时间复杂度是线性。由于该队列是作为链表实现的,因此必须遍历该列表,直到找到要删除的元素为止。使用 Iterator
,您已经找到了该元素,并且可以“就地”删除它。
如果您找到要删除的元素,并且它是队列中的最后一个元素怎么办?对该项目调用 remove
需要一直遍历到队列的末尾再次。此外,它需要为每个前面的元素调用 equals
。您绝对不想将要删除的项目放入列表中,因为您会具有相同的负面性能特征(以及另一个 List
的分配)。