我正在阅读“实践中的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)?
谢谢,伙计们。
答案 0 :(得分:1)
通过检查shutdownRequested
然后将消息放入队列,检查标志的生产者之间存在漏洞。如果发生关闭并且工作人员在这个微小的时间内停止执行,则会发生这种情况
虽然不太可能,但是当标志已经设置时,可能会将消息排入队列。
但我看不到生产者被阻止,因为工人只是忽略了关闭标志。
如果生产者在队列满时尝试将消息排队,则会阻塞,但当工作人员从队列中获取元素时,会被取消阻止。