程序在InterruptedException异常抛出后仍然继续运行

6

我开始学习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();
}

问题在于我期望看到以下输出:
task
task
task
task
task
interrupted

但是在我得到这个结果后,程序会一直打印输出,直到我关闭它。
那么我的问题是:我做错了什么?为什么程序会继续打印输出?

你尝试过使用 exec.shutdown() 而不是 exec.shutdownNow() 吗? - Sam DeHaan
exec.shutdown() 的效果更差。它甚至不能中断线程。 - Daniel S.
https://dev59.com/QUzSa4cB1Zd3GeqPlUkG - Eric J.
不仅要捕获中断异常,您还应该再次引发它以退出 while 循环。 - Maurício Linhares
4个回答

7

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


4

你仍然在while循环中,添加break或其他方式来跳出循环。

    catch (InterruptedException e) {
        System.out.println("interrupted");
        break;
    }

Java中的线程有点像一种合作活动,你被要求停下来,但你需要足够礼貌地实际执行。这样可以让线程在其消亡之前整理自己的事务。

正如Simon和Amir详细解释的那样,你的循环终止条件令人惊讶地不足够。


2
你需要使用isInterrupted,因为interupted()会清除标志位。 - Amir Raminfar

4
在关于并发的Java教程中,有一节关于中断的问题解释得很好: 中断状态标志 中断机制是使用称为中断状态的内部标志实现的。调用Thread.interrupt设置此标志。当线程通过调用静态方法Thread.interrupted检查中断时,中断状态被清除。另一个线程用于查询另一个线程的中断状态的非静态isInterrupted方法不会更改中断状态标志。 按照惯例,抛出InterruptedException退出的任何方法在这样做时都会清除中断状态。但是,另一个线程调用interrupt会立即再次设置中断状态。
因此,当您在循环内捕捉InterruptedException时,中断状态已经重置,因此下一次调用Thread.interrupted()将返回false,进而保持while循环运行。要停止循环,您有以下选项:
  • 使用break退出循环
  • 使用return退出整个方法
  • 将try-catch块移动到while循环之外(如Nathan Hughes所建议的)
  • 在当前线程上调用interrupt()以再次设置中断标志
  • 使用单独的布尔值控制循环,并在catch块中相应地设置该标志
  • 使用ScheduledExecutorService将任务作为重复任务执行,并从您的Runnable的run方法中删除循环

1
还有另一种选择:将try-catch移至while循环外部。 - Nathan Hughes

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接