关闭时了解关闭请求标志

时间:2016-04-10 08:19:10

标签: java multithreading queue

我正在阅读B. Goetz JCIP并在第7.2节中遇到一些关于取消基于线程的服务的误解。这是代码:

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");
 }

现在他说那个

  

日志的实施是chek-than-act sequnce:生产者可以   观察该服务尚未关闭但仍在排队   关机后的消息,再次冒着生产者的风险   可能会在日志中被阻止,永远不会被解锁

强调我并不清楚。

如果消费者将队列排到某个集合,它将使log()中的任何生产者被锁定。即使某些生产者尝试将日志消息放入队列,也不会被阻止。我看到的唯一一件事是,由于队列已耗尽,因此不会记录此消息。

问题: 为什么他说生产商很难被阻止而且从未解锁过。我错过了什么?

2 个答案:

答案 0 :(得分:1)

如果查看BlockingQueue doc,您可以看到:

  

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

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

答案 1 :(得分:1)

由于代码不完整,很难说出作者的意图。据推测,记录器线程还会检查shutdownRequested以停止记录:

public void run() {
    try{
        while(shutdownRequested)
           writer.println(queue.take());
    } catch(InterruptedException ignored){
    } finally {
        writer.close();
    }
 }

如果你写这个,考虑一个场景,当队列已满并且queue.put上有线程被阻塞时请求关闭:记录器线程停止调用queue.take并且这些线程永远被阻止。

即使不是这种情况,也存在变量shutdownRequested的竞争条件。线程可以请求在读取变量和消息在log方法中排队之间关闭,以便在请求关闭后消息仍然排队。