Producer-Consumer Logging服务具有不可靠的关闭方式

时间:2015-07-25 13:07:09

标签: java multithreading concurrency producer-consumer

我正在阅读“实践中的Java并发”,一个例子让我感到困惑,它是关于生产者 - 消费者日志服务的:

public class LogWriter {
    private final BlockingQueue<String> queue;
    private final LoggerThread logger;
    private boolean shutdownRequested = false;
    public LogWriter(Writer writer) {
        this.queue = new LinkedBlockingQueue<String>(CAPACITY);
        this.logger = new LoggerThread(writer);
    }
    public void start() { logger.start(); }
    public void shutdownlog() { shutdownRequested = true; }
    public void log(String msg) throws InterruptedException {
        if (!shutdownRequested)
            queue.put(msg);
        else
            throw new IllegalStateException("logger is shut down");
    }
    private class LoggerThread extends Thread {
        private final PrintWriter writer;
        ...
        public void run() {
            try {
                while (true)
                   writer.println(queue.take());
            } catch(InterruptedException ignored) {
            } finally {
                writer.close();
            }
        } 
    }
}

从书中可以看出,如果我们关闭它,它是不可靠的。它写道:

关闭LogWriter的另一种方法是设置“请求关闭”标志以防止提交更多消息,如清单7.14所示。然后,消费者可以在收到关闭已通知的情况下排空队列已被请求,写出任何待处理的消息并解除阻止在日志中阻止的任何生产者。但是,这种方法的竞争条件使其不可靠。 log的实现是一个checkthenact序列:生产者可以观察到服务尚未关闭但仍然在关闭后排队消息,同样存在生产者可能在日志中被阻塞的风险变得畅通无阻。有一些技巧可以降低这种可能性(就像让消费者在宣布队列耗尽之前等待几秒钟),但这些并没有改变根本问题,只会导致它导致失败的可能性。

我不太明白。是否意味着在shutdownflag设置为true后,另一个线程碰巧遇到queue.put(msg)?

谢谢,伙计们。

1 个答案:

答案 0 :(得分:1)

通过检查shutdownRequested然后将消息放入队列,检查标志的生产者之间存在漏洞。如果发生关闭并且工作人员在这个微小的时间内停止执行,则会发生这种情况 虽然不太可能,但是当标志已经设置时,可能会将消息排入队列。

但我看不到生产者被阻止,因为工人只是忽略了关闭标志。

如果生产者在队列满时尝试将消息排队,则会阻塞,但当工作人员从队列中获取元素时,会被取消阻止。