我正在阅读B. Goetz JCIP,并在7.2节中关于基于线程的cancellin服务遇到了一些误解。这是代码:
public class LogWriter{
private final BlockingQueue<String> queue;
private final LoggerThread logger;
public LogWriter(Writer writer){
this.queue = new LinkedBlockingQueue<String>(CAPACITY);
this.logger = new LoggerThread(writer);
}
public void start(){ logger.start(); }
public void log(String msg) throws InterruptedException {
queue.put(msg);
}
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();
}
}
}
他说,这种服务没有提供终止它的方法。他给出了另一种选择:
public void log(String msg) throws InterruptedException {
if(!shutdownRequested)
queue.put(msg);
else
throw new IllegalArgumentException("logger is shut down");
}
现在他说
日志的执行是先于后继的顺序:生产者可以
观察该服务尚未关闭但仍在排队
消息关闭后,再次冒着生产者的风险
可能会被阻止登录并且永远不会被解锁。
我对强调的内容不清楚。
如果使用者将队列中的内容排空到某个集合,它将使在
log()
中被阻止的所有生产者都被解锁。即使某些生产者尝试将日志消息放入队列,也不会被阻止。我看到的唯一一件事是,由于队列已耗尽,因此不会记录此消息。问题:为什么他说生产者会被封锁而永远不会被解锁。我错过了什么?
最佳答案
如果查看BlockingQueue
文档,您会看到:
一个队列,它另外支持等待队列的操作
在检索元素时变为非空,并等待空间
在存储元素时在队列中变得可用。
即如果队列中没有剩余空间,生产者可能会被阻塞:如果服务已关闭,队列将不再被耗尽。