Java BlockingQueue take() 在 while 循环中

Java BlockingQueue take() in a while loop

我有一个 BlockingQueue,它由一个使用 put() 的线程填充。但是我对如何为 BlockingQueue 执行 take() 感到困惑。目前我是这样实现的:

String link;
try {
    while(!(link = links.take()).isEmpty()) {
        System.out.println(link);
    }
} catch(InterruptedException ex) {
    ex.printStackTrace();
}

是吗?如果不在条件语句中,如何循环队列并分配字符串变量?

我的理解是您在询问如何以一种好的方式终止 BlockingQueue。我能想到两种情况。在任何情况下,您都有消息生产者 A 和消息消费者 B。

  1. 消息生产者发送某种形式的终端值,如 "Stop"。您检查它,while 循环终止。
  2. 您可以中断消息生产者,这将在消费者端抛出 InterruptedException。这是避免终端输入情况的方法。这里的问题是,如果消费者实际上已经消费了队列中的所有内容,您将无法控制。所以中断通常在有条件要求消费立即终止时使用。

如果我没理解错的话,你问的是take条件之外的方法?好吧,这并不难:

while (!links.isEmpty()) {
    try {
        String link = links.take();
        // Do stuff.
    } catch (InterruptedException e) {
        // Exception handling.
    }
}

您当前的条件 !(link = links.take()).isEmpty() 检查 return 值(字符串)是否为空(长度等于 0),而不是队列。

无论如何,请记住上面的代码不是 atomic,因此不能保证 links.isEmpty()links.take() 之间不会发生任何其他事情。

编辑: 您可以在启动期间使用标志处理 race conditions

BlockingQueue<Integer> numbers = new ArrayBlockingQueue<>(10);
AtomicBoolean flag = new AtomicBoolean(true);

// Producer.
new Thread(() -> {
    for (int i = 0; i < 10; i++) {
        try {
            numbers.put(i);
        } catch (InterruptedException e) { /* NOP */ }
    }
    flag.set(false);
}).start();

// Consumer.
while (flag.get() || !numbers.isEmpty()) {
    try {
        System.out.println(numbers.take());
    } catch (InterruptedException e) { /* NOP */ }
}

AtomicBoolean is not necessary here, but it might become handy if you have multiple producers and/or consumers. It's also part of java.util.concurrent 你绝对应该检查一下。