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

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

4

4 回答 4

7

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

于 2011-08-12T17:08:17.977 回答
4

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

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

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

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

于 2011-08-12T17:05:55.327 回答
4

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

中断状态标志

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

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

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

  • 用于break退出循环
  • 用于return退出整个方法
  • 将 try-catch-block 移到 while 循环之外(如 Nathan Hughes 建议的那样)
  • 在当前线程上调用interrupt()再次设置中断标志
  • 使用单独的布尔值来控制循环并在 catch-block 中相应地设置该标志
  • ScheduledExecutorService通过使用 a并从你的 run-method 中删除循环使任务成为重复任务Runnable
于 2011-08-12T17:20:44.873 回答
1

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

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

于 2011-08-12T17:07:50.410 回答