错过了中断,除非你使用Thread.interrupted()?

时间:2018-03-26 20:15:56

标签: java multithreading

我对Java教程中的以下示例有疑问:https://docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}

Java教程似乎建议这样可以很好地处理异常,因为大部分执行时间将花在Thread.sleep()中,如果线程收到中断,则会抛出InterruptedException。

但是,如果在代码执行println时收到中断,则此示例无法完全错过中断?因此,最安全的做法是修改它,如下所示(添加另一个调用Thread.interrupted())?

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        if (Thread.interrupted()){
            throw new InterruptedException()
        }
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}

但实际上,如果是这样的话,我们永远不能依赖InterruptedException来提供帮助,除非我们有时会错过它,或者如果我们在一个循环或其他东西中断了Threads。我错过了什么?

1 个答案:

答案 0 :(得分:6)

没有。中断线程会设置一个标志,下次调用Thread.sleep(...)时会检查该标志。

因此,即使中断发生时它不在Thread.sleep中,也不会丢失中断。

要做的一件重要事情是在捕获InterruptedException时重新中断线程:

} catch (InterruptedException e) {
  Thread.currentThread().interrupt();

  // ...
}

这允许此方法之外的代码知道此方法提前完成的原因是因为中断;它也应该处理中断。如果run()方法直接由Thread执行,则这可能无关紧要;但这不是运行该方法的唯一方法。

顺便说一下,编写该代码的一种更简洁的方法是捕获循环外的中断:

try {
    for (int i = 0; i < importantInfo.length; i++) {
        // Pause for 4 seconds
        Thread.sleep(4000);

        // Print a message
        System.out.println(importantInfo[i]);
    }
} catch (InterruptedException e) {
    // We've been interrupted: no more messages.
    Thread.currentThread().interrupt();
}

我发现外面这样做更清楚,因为它清楚地表明中断会停止循环迭代