我正在阅读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文档,您会看到:


  一个队列,它另外支持等待队列的操作
  在检索元素时变为非空,并等待空间
  在存储元素时在队列中变得可用。


即如果队列中没有剩余空间,生产者可能会被阻塞:如果服务已关闭,队列将不再被耗尽。

08-04 09:25