【问题标题】:Program continues to run despite InterruptedException尽管出现了 InterruptedException,程序仍继续运行
【发布时间】:2011-08-12 17:00:55
【问题描述】:

我开始学习 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()吗?
  • exec.shutdown() 效果更差。它甚至不会中断线程。
  • 不只是捕捉中断的异常,你应该再次引发它以摆脱这段时间。

标签: java multithreading concurrency executor


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    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 的运行方法中删除循环,使任务成为重复任务

    【讨论】:

    • 还有另一种选择:将 try-catch 移到 while 循环之外。
    【解决方案3】:

    您仍在 while 循环中,添加一个 break 或其他方式退出循环。

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

    Java 中的线程是一种合作活动,您被要求停止,但您需要有足够的礼貌才能真正做到这一点。这允许线程有时间在其消亡之前整理其事务。

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

    【讨论】:

    • 你需要使用 isInterrupted 因为 interupted() 清除标志。
    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-03
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多