为什么Thread.sleep()会清除中断标志?

3

我知道一些Thread方法会清除中断标志(例如sleep,wait等)。 但他们为什么这样做呢?这是什么原因?


@Zoyd:这个问题并没有确切地解释“为什么”。 - Nathan Hughes
2个回答

6
这是中断设计的结果,它并不完全等同于取消。Oracle的指导意见是仅将中断用于取消,但这个观点可能是随着时间而形成的。无论如何,设计并没有强制要求这样做。您可以设计一个任务以响应中断,然后返回到原来的工作状态。
在《Java并发编程实战》第7.1章第138页中写道:
“API或语言规范中没有任何将中断与特定取消语义绑定在一起的内容,但在实践中,除了取消之外,使用中断是脆弱的,并且在更大的应用程序中难以维护。”
按照设计,任何时候都只有一件事情,即InterruptedException被捕获或中断标志,以告知线程的状态。如果InterruptedException正在执行,则标志的值无关紧要。而且这个想法似乎是由捕获异常的代码决定是否设置中断标志。
这样,使用InterruptedException退出循环就很方便:
try {
    while (!Thread.currentThread().isInterrupted()) {
        Thread.sleep(5000);
        // ... do stuff ...
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

由于异常被捕获在循环外部,因此线程停止循环,只有周围的代码是否设置了中断标志才有关系。但是,如果你在循环内部捕获InterruptedException,就像下面这样:

while (!Thread.currentThread().isInterrupted()) {
    // ... do stuff ...
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

许多代码都这样做,因为程序员们被灌输过一定不要甚至想到使用异常来控制流程。如果是这样,那么你需要设置中断标志。

我认为意图是应用程序开发人员应该使用异常来跳出中断的上下文,将异常消耗在源头附近并不干净。


4
简而言之,因为这些方法将线程发送到“新鲜”的等待状态(在被中断后重新进入运行状态)。之前设置的“中断”标志不再适用,因为该线程自进入新的等待状态以来没有被中断过。

这可能是最好的答案,但需要详细说明线程状态、阻塞IO、异常和标志在这个问题中的关系。 - sevo

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