【问题标题】:Understanding shutdown requested flag when shutting down关闭时了解关闭请求标志
【发布时间】:2016-04-10 18:20:32
【问题描述】:

我正在阅读 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");
 }

现在他这么说

日志的实现是 chek-than-act sequnce:生产者可以 观察到服务还没有关闭但是还在排队 关闭后的消息,再次生产者有风险 可能会在日志中被阻止并且永远不会解锁

强调的内容我不清楚。

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

问题:他为什么说生产者必须被阻止并且永远不能解锁。我错过了什么?

【问题讨论】:

  • 你能发布完整的代码吗? shutdownRequested 是仅在 log 方法中使用,还是在记录器线程中使用?
  • @Joni 这就是完整的。他没有提供更多细节。
  • @Joni logger 线程是一个内部类

标签: java multithreading queue


【解决方案1】:

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

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

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

【讨论】:

  • 但是当请求关闭时,我们只需将标志设置为true,然后消费者排空队列。因此,log() 中等待的所有记录器都已解锁。唯一可能发生的情况是大于队列容量的线程数会重现这种竞争条件......
  • 我同意,这应该只适用于多线程和小容量的情况。但仍有可能。
【解决方案2】:

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

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

如果您编写此代码,请考虑以下情况:当队列已满并且queue.put 上存在线程阻塞时请求关闭:记录器线程停止调用queue.take,并且这些线程永远保持阻塞状态。

即使不是这样,变量shutdownRequested 也存在竞争条件。线程可能会在读取变量和消息在log 方法中排队之间请求关闭,因此在请求关闭后消息仍会排队。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-24
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 2023-03-06
    • 1970-01-01
    相关资源
    最近更新 更多