【发布时间】:2015-07-26 14:16:05
【问题描述】:
我正在阅读“实践中的 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 序列:生产者可以观察到服务尚未关闭,但关闭后仍然排队消息,同样存在生产者可能在 log 中被阻塞并且永远不会出现的风险变得畅通无阻。有一些技巧可以降低这种可能性(比如让消费者在宣布队列耗尽之前等待几秒钟),但这些不会改变根本问题,只会改变它导致失败的可能性。
我不太明白。这是否意味着另一个线程恰好在shutdownflag设置为true之后遇到了queue.put(msg)?
谢谢各位。
【问题讨论】:
-
不应该是线程循环中的
while(!shutdownRequested)吗?更不用说布尔值对于多线程使用必须是可变的。 -
@the8472,我想我们不应该在消费者循环中使用 !shutdownRequested 。消费者一直在不断地运行,试图完成从队列中取出项目的工作。对于易失性,我完全同意你的看法:)
标签: java multithreading concurrency producer-consumer