为什么InterruptedException清除线程的中断状态?

时间:2010-03-26 13:52:42

标签: java multithreading

如果线程在Object.wait()Thread.join()内被中断,则会抛出InterruptedException,重置线程的中断状态。例如,如果我在Runnable.run()内有这样的循环:

while (!this._workerThread.isInterrupted()) {
    // do something
    try {
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
    } catch (InterruptedException e) {
        if (!this._isStopping()) {
            this._handleFault(e);
        }
    }
}

线程将在调用interrupt()后继续运行。这意味着我必须通过在循环条件中检查自己的停止标志,重新抛出异常或添加break来明确地突破循环。

现在,这不是一个问题,因为这种行为有很好的记录,并不妨碍我按照我想要的方式做任何事情。但是,我似乎并不理解它背后的概念:为什么抛出异常后线程不再被视为中断?如果您使用interrupted()而不是isInterrupted()获得中断状态,也会出现类似行为,那么线程也只会出现中断一次。

我在这里做些不寻常的事吗?例如,在循环外捕获InterruptedException更常见吗?

(即使我不是一个初学者,我也标记了这个“初学者”,因为对我来说这看起来像是一个非常基本的问题,看着它。)

4 个答案:

答案 0 :(得分:8)

这个想法是应该处理一次中断。如果显式InterruptedException没有清除“中断”标志,则InterruptedException的大多数捕获者必须明确清除该标志。相反,你可以通过自我中断(Thread.currentThread().interrupt())“清除”旗帜。 Java的设计人员一直在寻找能够在大多数时间保存击键的语义(即你更经常要清除标志而不是设置它)。

答案 1 :(得分:1)

像这样编写你的代码,你不需要一个标志:

try {
    while (!this._workerThread.isInterrupted()) {
        // do something
        synchronized (this) {
            this.wait(this._waitPeriod);
        }
        // do something else
    }
} catch (InterruptedException e) {
    // ignore ...
}

正如@Boyan指出的那样,一般来说,压制中断异常是个坏主意。在这种情况下,上下文将确定是否应该压缩它(如上所述),设置中断标志(再次)或允许异常传播。除其他外,它取决于中断对应用程序的意义。

答案 2 :(得分:1)

不应该。这是一个令人遗憾的设计缺陷,使得依赖中断成为一项有风险的业务,因为库代码通常会捕获DateTime而不重置线程的中断标志并继续进行。如果您碰巧在运行该特定的损坏的库代码时发出线程中断信号,那么当您的代码重新获得执行控制时,它将不会发现中断发生的线索。

这只需要在你从代码中调用的任何地方发生一次,所以为了能够中断一个线程,然后使用被中断的位来安全地从所述线程内部控制你的流,你需要100%确定你所调用的每一段代码都不会错误地清除被中断的位。当涉及到库时,这很难做到,但即使您可以说明您在代码中使用的每个库,仍然不会考虑buggy JRE code that can make the same mistake

它只需要一个库(或JRE!)作者不关心或考虑中断以打破需要它的代码逻辑,这表明这是错误的默认操作。不关心线程中断位的人可能不会在捕获InterruptedException之后重置它 - 也许他们甚至不知道它存在!如果捕获InterruptedException没有重置线程的中断状态,那么任何不知道被中断位的人都会自动“做正确的事”并且不会因依赖中断的任何调用代码而导致问题。任何需要清除它的人仍然可以手动执行此操作,但随后它将是一个明确的操作,这比捕获已检查的InterruptedException异常的通常无意的副作用更可能是正确的。就目前而言,如果你依赖线程的中断位,那么任何不小心调用InterruptedException的调用堆栈中的任何人都可能会毁掉你的一天。

因此,大多数Java多线程代码只会使用“isRunning”实例字段复制Java线程中断模型,并使用某种机制将其作为解决方法进行翻转。

答案 3 :(得分:0)

那是因为InterruptedException被认为是一个异常事件,其他人试图从外面阻止一个线程。

当你想真正打断一个线程时,你只需通过设置一个布尔值或类似的东西来打破它的循环条件。或者您在该帖子中使用.wait().notify() 。但如果您在外部wait()

  • 抛出异常以通知外部线程试图打断我或让我等待
  • 线程继续工作,因为它不接受来自另一个线程的任何订单!但是异常的提升允许你添加特殊处理并做任何你想做的事情,也可以有效地阻止线程。