当实现Runnable时,为什么要使用Thread.currentThread().isInterrupted()而不是Thread.interrupted()?

12

在stackoverflow上,我经常看到使用Thread.currentThread().isInterrupted()。当实现Runnable并在while循环中使用它时,就像这样:

public void run() {
  while(!Thread.currentThread().isInterrupted()) { ... }
}

除了使用 interrupted() 时清除了 interrupted 标志之外,使用 Thread.interrupted() 是否有任何不同之处?

我也看到过 Thread.currentThread().interrupted()。那是正确的使用方式吗,还是只使用 Thread.interrupted() 就足够了?


http://stackoverflow.com/questions/4801317/whats-the-difference-between-thread-interrupt-and-thread-currentthread-interr - itzhaki
@itzhaki 这不是一个有用的链接。它是关于interrupt方法的。 - Marko Topolnik
4个回答

9

正如您所说,两者的区别在于一个清除线程的中断状态,另一个则不会。既然您已经知道了这一点,那么您真正想问的似乎是保留线程中断状态是否很重要。

首先,必须确定检查中断状态(或处理InterruptedException)的代码是否被视为线程的“所有者”。如果是这样,在某些有限的情况下,可以适当地吞掉(或只是不抛出)InterruptedException以及中断状态,因为所有者正在实现线程的取消策略(Goetz,《Java并发编程实践》,第143页)。

但在绝大多数情况下,包括Runnable,相关代码都不是线程所有者,因此不能吞掉取消状态。在这种情况下,您有两个选择:

  • 保留线程中断状态,但抛出InterruptedException。(这就是Thread.sleep()的做法。)
  • 保留中断状态。

对于Runnable,您无法抛出已检查异常,因为run()没有声明如此。 (反过来,我推测它是这样设计的,因为通常没有人去捕获它。)因此,您唯一的选择是保留取消状态。

鉴于上述解释,让我回到您的直接问题。首先,如果您想检查取消状态并保留它,那么编写以下代码会更容易:

if (Thread.currentThread().isInterrupted()) doSomething;

than

if (Thread.interrupted()) {
    Thread.currentThread().interrupt();
    doSomething;
}

此外,就像你最初的问题一样,如果你在一个while循环中使用Thread.interrupted()作为条件,在循环结束后你将无法确定它是因为Thread.interrupted()返回了true还是其他条件改变或者break语句运行了。所以在这种情况下使用Thread.currentThread().isInterrupted()实际上是你唯一的选择。(当然,你也可以编写循环,使其唯一的退出原因是线程已被中断,但这种代码容易出问题,因为在循环后你必须重新中断线程,如果有人后来改变了代码,也会因其他原因而退出循环,那么你就会在原本没有被中断的情况下中断线程。)
对于你的第二个问题,正如其他人所说,绝对不要使用Thread.currentThread().interrupted(),因为这很具有误导性。由于interrupted()是一个静态方法,在这种情况下如果你使用-Xlint编译器,则会得到一个有用的警告:
警告:[static] static method should be qualified by type name, Thread, instead of by an expression
类似的工具也可能会采取相同的做法,比如Eclipse会显示:
The static method interrupted() from the type Thread should be accessed in a static way

6

仅回答您问题的最后一部分...

我也见过 Thread.currentThread().interrupted()。那是正确的使用方式吗,还是使用 Thread.interrupted() 就足够了?

从纯函数的角度来看,这两种方法意义完全相同。

但从可读性的角度来看,

    Thread.currentThread().interrupted()

看起来像是在调用一个实例方法...但实际上并不是。因此,

    Thread.interrupted()

更好。绝对不要这样做:
    Thread someThread = ...
    someThread.interrupted()

看起来你正在测试someThread,但实际上你测试的是当前线程。非常具有误导性!


@sjlee - 我的回答没有涉及到 isInterrupted。请看第一句话。 - Stephen C

3
在这里,差异非常微妙,通常并不重要。您可以根据需要明确或清除中断状态。甚至没有一个标准的惯例说“使用其中之一而永远不使用另一个”。
主要的是要知道如何使用中断标志:让它处于您没有具体意图的状态肯定会产生显著的区别。
绝对不要使用Thread.currentThread().interrupted()。这只会引起误解,特别是如果您有someOtherThread.interrupted()

在我查看的文档中,“interrupted”是静态的,因此调用Thread.currentThread().interrupted()是否多余? - cmbaxter
这不仅仅是不必要的,但我认为OP的问题主要不是关于那个区别,而更多地是一个次要的方面。 - Marko Topolnik

0
除了使用`interrupted()`时会清除中断标志外,还有什么不同吗?不,但那是非常重要的不同。如果您只像在示例中一样在线程的`run`方法中单独的`while`循环内使用它,以便在线程被中断时退出`run`方法,则没有区别,但在其他场景中可能会有所不同。例如,想象一下嵌套循环,每个循环都检查中断状态(并在外部循环得到检查前清除状态...)关于`Thread.currentThread().interrupted()`与`Thread.interrupted()`之间的差异,没有功能上的区别,但后者更短,因此请使用它。

1
前者在许多默认配置的IDE中也会生成警告,这是一个非常好的警告。 - Marko Topolnik
@marko,如果没有任何区别,为什么警告这件事情是一件好事呢? - Christian
这是因为它通常表示程序员错误,本意是调用实例方法,任何未来的读者都可能误解这种表达的含义。 - Marko Topolnik

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