尽管InterruptedException,程序仍继续运行

时间:2011-08-12 17:00:55

标签: java multithreading concurrency 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();
}

问题在于我希望看到以下输出:

task
task
task
task
task
interrupted

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

4 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:4)

你仍处于while循环中,在循环中添加一个中断或其他方式。

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

Java中的线程是一种合作活动,你被要求停止,但你需要礼貌地实际做到这一点。这允许线程时间在其消亡之前整理其事务。

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

答案 2 :(得分:4)

关于Java tutorials about concurrency中断的部分很好地解释了这个问题:

  

中断状态标志

     

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

     

按惯例,通过抛出一个退出的任何方法   InterruptedException在清除时会清除中断状态。但是,   始终可以立即设置中断状态   再次,由另一个线程调用中断。

因此,当你在循环中捕获InterruptedException时,中断的状态已经被重置,因此,下一次调用Thread.interrupted()将返回false,这反过来使while循环继续运行。要停止循环,您有以下选项:

  • 使用break退出循环
  • 使用return退出整个方法
  • 将try-catch-block移动到while循环之外(由Nathan Hughes建议)
  • 在当前线程上调用interrupt()以再次设置中断标志
  • 使用单独的布尔值来控制循环并在catch-block
  • 中相应地设置该标志
  • 使用ScheduledExecutorService并从Runnable
  • 的run-method中删除循环,使任务成为定期任务

答案 3 :(得分:1)

“除了尽力尝试停止处理主动执行任务之外没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此如果任何任务屏蔽或无法响应中断,它们可能永远不会终止。“

来源:http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ExecutorService.html#shutdownNow()