从 ConcurrentLinedQueue 中迭代和删除元素

问题描述

我定义了一个 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 的分配)。