在取出所有阻塞队列元素后,等待它们处理

时间:2018-08-14 19:14:31

标签: java multithreading concurrency blockingqueue

在以下情况下,终结器线程必须等待使用者线程处理所有队列元素才能完成执行:

private final BlockingQueue<Object> queue = new LinkedBlockingQueue<>();
private final Object queueMonitor = new Object();

// Consumer thread
while (true) {
    Object element = queue.take();
    consume(element);
    synchronized (queueMonitor) {
        queueMonitor.notifyAll();
    }
}

// Finalizer thread
synchronized (queueMonitor) {
    while (!queue.isEmpty()) {
        queueMonitor.wait();
    }
}

元素随时间添加到队列中。 使用者守护程序线程一直运行直到JVM终止为止,此时必须允许它完成所有排队元素的处理。 当前,这是通过终结器线程完成的,该终结器线程是一个关闭钩子,应在JVM终止时延迟终止使用者线程。

问题:
如果在从队列中取出最后一个元素之后启动了终结器线程,则while循环条件的计算结果为false,因此consume()尚未返回,因为等待{{1 }}被完全跳过。

研究
理想的解决方案是先peek the queue,然后在元素消耗完后将其删除。

1 个答案:

答案 0 :(得分:3)

一种方法可能是您使用CountDownLatch –在其上有finalizer块,并在consume()之后倒置消费者呼叫倒数。

基本上不在队列上阻塞,而在任务完成时阻塞。

private final BlockingQueue<Object> queue = new LinkedBlockingQueue<>();
private volatile boolean running = true;
private final CountDownLatch terminationLatch = new CountDownLatch(1);

// Consumer thread
while (running || !queue.isEmpty()) {
    Object element = queue.poll(100, TimeUnit.MILLISECONDS);
    if (element == null) continue;
    consume(element);
}
terminationLatch.countDown();

// Finalizer thread
running = false;
terminationLatch.await();