尽管InterruptedException,程序仍继续运行

Dan*_* S. 6 java concurrency multithreading executor

我开始学习java,现在我正处于并发章节.在阅读了一些关于并发的内容后,我尝试了一个自己的例子.

public class Task implements Runnable{

public void run() {
    while(!Thread.interrupted()) {
        try {
            System.out.println("task");
            TimeUnit.SECONDS.sleep(2);
        }catch (InterruptedException e) {
            System.out.println("interrupted");
        }
    }
}

}

public static void main(String[] args) throws Exception {
    ExecutorService exec = Executors.newCachedThreadPool();
    exec.execute(new Task());
    TimeUnit.SECONDS.sleep(10);
    exec.shutdownNow();
}
Run Code Online (Sandbox Code Playgroud)

问题是我期待看到以下输出:

task
task
task
task
task
interrupted
Run Code Online (Sandbox Code Playgroud)

但是在我得到这个之后,程序会继续打印,直到我关闭它.
所以,我的问题是我做错了什么?为什么程序继续打印?

JB *_*zet 7

当您关闭执行程序时,它会尝试通过中断它们来停止其正在运行的任务.这会导致抛出InterruptedException,但您只是吞下它并继续.您应该在catch子句中返回,和/或通过调用Thread.currentThread.interrupt()重置线程的中断状态,这将重置中断状态并退出循环.


Sim*_*ann 4

Java教程中有关并发的中断部分很好地解释了这个问题:

中断状态标志

中断机制是使用称为中断状态的内部标志来实现的。调用 Thread.interrupt 设置此标志。当线程通过调用静态方法 Thread.interrupted 检查中断时,中断状态将被清除。非静态 isInterrupted 方法由一个线程用来查询另一个线程的中断状态,不会更改中断状态标志。

按照约定,任何通过抛出 InterruptedException 退出的方法都会在这样做时清除中断状态。然而,中断状态总是有可能被另一个调用中断的线程立即再次设置。

因此,当您在循环中捕获 InterruptedException 时,中断状态已经重置,因此,下一次调用 Thread.interrupted() 将返回 false,这又使 while 循环保持运行。要停止循环,您有以下选择:

  • 用于break退出循环
  • 用于return退出整个方法
  • 将 try-catch-块移动到 while 循环之外(按照 Nathan Hughes 的建议)
  • 在当前线程上调用interrupt()再次设置中断标志
  • 使用单独的布尔值来控制循环并在 catch 块中相应地设置该标志
  • ScheduledExecutorService通过使用 a并从运行方法中删除循环,使该任务成为重复任务Runnable