如何在不阻塞使用流的情况下处理队列的所有元素?

Gra*_*oss 1 java queue java-stream

假设我有一个Queue<String>,我想清空队列的当前内容并对每个元素做一些事情。使用循环我可以做类似的事情:

while (true) {
    String element = queue.poll();
    if (element == null) {
        return;
    }
    System.out.println(element);
}
Run Code Online (Sandbox Code Playgroud)

这感觉有点丑。我可以用流做得更好吗?

请注意,可能有其他线程同时访问队列,因此依赖队列的大小来知道要轮询的项目数量很容易出错。

Hol*_*ger 5

既然您问的是“无阻塞”,那么您似乎指的是BlockingQueue. 在这种情况下,建议避免重复调用poll().

相反,将所有待处理元素一次性转移到本地集合,然后处理它们:

List<String> tmp = new ArrayList<>();
queue.drainTo(tmp);
tmp.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

您还可以避免System.out(隐式)多次同步:

List<String> tmp=new ArrayList<>();
queue.drainTo(tmp);
System.out.println(tmp.stream().collect(Collectors.joining(System.lineSeparator())));
Run Code Online (Sandbox Code Playgroud)

或者

List<String> tmp=new ArrayList<>();
queue.drainTo(tmp);
System.out.println(String.join(System.lineSeparator(), tmp));
Run Code Online (Sandbox Code Playgroud)

(虽然这不承担流操作)...

  • @Eugene:如果你`poll` *n* 个元素,你阻塞队列的时间至少与通过`drainTo` 传输*n* 个项目时阻塞队列的时间相同。通常,使 *n* 个不同的调用锁定 *n* 次的开销要高得多,导致阻塞时间比只执行一次锁定操作的 `drainTo` 要长得多。如果您试图优化最大暂停时间,您可以将 *maxElements* 参数传递给 `drainTo` 并确保目标列表的容量是相同的。 (2认同)
  • @Graeme Moss:如果你想支持并发的 `add` 操作,使用 `ConcurrentLinkedQueue` 和 `poll()` 可能是正确的事情,但这实际上不符合“*我想清空”的心态queue*”任务的当前内容。在允许并发添加的情况下进行轮询时,没有实际的“当前内容”。 (2认同)