Java并发在实践中的应用&x201C;清单7.15。向LogWriter添加可靠的取消;。loggerThread.interrupt()的作用是什么?

Java并发在实践中的应用&x201C;清单7.15。向LogWriter添加可靠的取消;。loggerThread.interrupt()的作用是什么?,java,multithreading,Java,Multithreading,我在实践中阅读Java并发性,遇到以下代码片段(清单7.15.向LogWriter添加可靠的取消) 公共类日志服务{ 私有最终阻塞队列; 专用最终LoggerThread LoggerThread; 私人最终印刷作家; @GuardedBy(“此”)私有布尔值设置; @由(“本”)私人int保留担保; public void start(){loggerThread.start();} 公共停车场(){ 已同步(此){IsShutton=true;} loggerThread.interrupt

我在实践中阅读Java并发性,遇到以下代码片段(清单7.15.向LogWriter添加可靠的取消)

公共类日志服务{
私有最终阻塞队列;
专用最终LoggerThread LoggerThread;
私人最终印刷作家;
@GuardedBy(“此”)私有布尔值设置;
@由(“本”)私人int保留担保;
public void start(){loggerThread.start();}
公共停车场(){
已同步(此){IsShutton=true;}
loggerThread.interrupt();
}
公共无效日志(字符串msg)引发InterruptedException{
已同步(此){
如果(isShutdown)
抛出新的非法状态异常(…);
++保留;
}
queue.put(msg);
}
私有类LoggerThread扩展线程{
公开募捐{
试一试{
while(true){
试一试{
已同步(LogService.this){
如果(isShutdown&&reservations==0)
打破
}
字符串msg=queue.take();
已同步(LogService.this){
--保留;
}
writer.println(msg);
}捕获(InterruptedException e){/*重试*/}//中断策略
}
}最后{
writer.close();
}
}
}
}
LogService
用于实现“多日志生产者,单日志消费者”(多个线程可以执行
log(String msg)
任务以将日志放入
队列
,一个
loggerThread
可以使用
队列
中的日志)


但是
LoggerThread
已经定义了自己的中断策略,即catch块中的“不做任何事情”。那么,调用
loggerThread.interrupt()有什么意义

如果我们查看循环:

while(true){
试一试{
已同步(LogService.this){
如果(isShutdown&&reservations==0)
打破
}
字符串msg=queue.take();
已同步(LogService.this){
--保留;
}
writer.println(msg);
}捕获(InterruptedException e){/*重试*/}//中断策略
}
我们看到它有以下行为:

  • 线程在
    队列中阻塞。take()
    ,等待传入消息
  • 只要
    LogService
    尚未关闭或仍有消息要记录,它就会循环
  • 关闭时,如果队列中仍有消息,则在循环终止之前将记录这些消息
  • 如果线程在没有关闭
    LogService
    的情况下以某种方式被中断,那么线程将继续运行,就像没有任何更改一样。这可以防止错误中断中断服务
catch
块中无需执行任何操作,因为要跳出循环的代码在循环的其他地方处理。如果您愿意,您可以:

catch(InterruptedException-ex){
已同步(LogService.this){
如果(isShutdown&&reservations==0)中断;
}
}
但这将是重复的,多余的代码,没有理由。我们也不希望在
catch
块中出现无条件的
break
,因为我们希望循环,直到所有消息都被记录,即使在关机之后;同样,您可以将该逻辑放在
catch
块中,但是当循环的其余部分已经做了完全相同的事情时,为什么要这样做呢


我们需要调用
loggerThread.interrupt()
,因为线程可能在
队列.take()调用中被阻塞。中断唤醒线程,允许它检查中断循环条件。如果没有中断,线程可以保持阻塞状态,并且永远不会消亡。

“此设置”==“在catch块中不执行任何操作”?如果是的话,最好把它说得更清楚。这不仅仅是在catch块中什么都不做,而是整个循环。我编辑了我的答案,试图把更多的注意力放在空的
catch
块上。它有用吗?我认为
loggerThread.interrupt()
用于防止一种特定情况,但不是所有
queue.take
阻止调用。一种特定的情况是“当
loggerThread
执行
时,如果(isshutton&&reservations==0)
,它会看到
isshutton
为false,reservations为0,但在调用
queue.take()
之前,有人调用了
stop
”。如果
loggerThread.interrupt()
不在块中,
loggerThread
将永远被阻止。实际上这两者都有一点。如果服务在调用
take()
之前关闭,但在检查
isShutdown
之后关闭,则调用
take()
将立即引发
中断异常。然而,在我看来,这种情况需要不太可能的时机;在调用
take()
时,线程更有可能被阻塞。但这并不重要,因为效果是一样的。
public class LogService {
    private final BlockingQueue<String> queue;
    private final LoggerThread loggerThread;
    private final PrintWriter writer;
    @GuardedBy("this") private boolean isShutdown;
    @GuardedBy("this") private int reservations;
    public void start() { loggerThread.start(); }
    public void stop() {
        synchronized (this) { isShutdown = true; }
        loggerThread.interrupt();
    }
    public void log(String msg) throws InterruptedException {
        synchronized (this) {
            if (isShutdown)
                throw new IllegalStateException(...);
            ++reservations;
        }
        queue.put(msg);
    }
    private class LoggerThread extends Thread {
        public void run() {
            try {
                while (true) {
                    try {
                        synchronized (LogService.this) {
                            if (isShutdown && reservations == 0)
                                break;
                        }
                        String msg = queue.take();
                        synchronized (LogService.this) {
                            --reservations;
                        }
                        writer.println(msg);
                    } catch (InterruptedException e) { /* retry */ } // interruption policy
                }
            } finally {
                writer.close();
            }
        }
    }
}