Java BlockingQueue在while循环中使用take()

时间:2016-07-17 05:42:26

标签: java asynchronous blockingqueue

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

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

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

2 个答案:

答案 0 :(得分:1)

我的理解是,您正在询问如何以良好的方式终止BlockingQueue。我能想到两种情况。在任何情况下,您都有消息生成器A和消息使用者B.

  1. 消息生产者发送某种形式的终端值,如“停止”。您检查它并且while循环终止。
  2. 您可以中断消息生成器,它将在消费者端抛出InterruptedException。这是避免终端输入情况的方法。这里的问题是,如果消费者实际上已经消耗了队列中的所有内容,那么你就无法控制。因此,如果存在需要消费终止的情况,通常会使用中断。

答案 1 :(得分:1)

如果我理解正确,你已经要求在条件之外找到take的方法吗?嗯,这并不难:

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

您当前的条件!(link = links.take()).isEmpty()检查返回值 - 字符串 - 是否为空(长度等于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,但如果您有多个生产者和/或消费者,它可能会变得很方便。它也是java.util.concurrent的一部分你绝对应该结帐。