为啥在实现 Runnable 时使用 Thread.currentThread().isInterrupted() 而不是 Thread.interrupted()?

Posted

技术标签:

【中文标题】为啥在实现 Runnable 时使用 Thread.currentThread().isInterrupted() 而不是 Thread.interrupted()?【英文标题】:Why use Thread.currentThread().isInterrupted() instead of Thread.interrupted() when implementing Runnable?为什么在实现 Runnable 时使用 Thread.currentThread().isInterrupted() 而不是 Thread.interrupted()? 【发布时间】:2013-05-30 18:07:02 【问题描述】:

在***上,我经常看到Thread.currentThread().isInterrupted()的使用。在实现Runnable 并在while 循环中使用它时,如下所示:

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

使用Thread.interrupted() 有什么不同(除了interrupted 标志在使用interrupted() 时被清除)?

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

【问题讨论】:

***.com/questions/4801317/… @itzhaki 这不是一个有用的链接。这是关于interrupt 方法的。 【参考方案1】:

正如您所说,不同之处在于一个清除线程的中断状态而一个不清除。既然您已经知道这一点,那么您似乎真正要问的是保持线程的中断状态是否重要。

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

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

清除线程中断状态但抛出InterruptedException。 (这就是Thread.sleep() 所做的。) 保留中断状态。

Runnable 的情况下,您不能抛出已检查异常,因为未声明run() 这样做。 (反过来,我推测它是这样设计的,因为通常不会有人抓住它。)所以你唯一的选择是保留取消状态。

鉴于上述解释,让我回到您的直接问题。首先,如果要查看取消状态并保存,写起来比较容易

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

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

此外,与您最初的问题一样,如果您在while 循环中使用Thread.interrupted() 作为条件,在循环中断后您将不知道它是否终止,因为Thread.interrupted() 返回true 或其他一些条件改变或运行了break 语句。所以在那种情况下使用Thread.currentThread().isInterrupted() 真的是你的only 选项。 (当然,您也可以编写循环,使其退出的 only 原因是线程被中断,但是您的代码会很脆弱,因为在循环之后您必须重新中断线程如果后来其他人出现并更改代码以也出于其他原因跳出循环,那么您将在线程最初未被中断时中断该线程。)

对于您的第二个问题,正如其他人所说,永远不要使用Thread.currentThread().interrupted(),因为它具有误导性。由于interrupted() 是一个静态方法,在这种情况下,如果您使用-Xlint 编译,编译器会给您一个有用的警告:

警告:[静态] 静态方法应由类型名称 Thread 限定,而不是由表达式限定

其他一些工具可能会做类似的事情,比如 Eclipse,它会显示:

Thread 类型的静态方法 interrupted() 应该以静态方式访问

【讨论】:

【参考方案2】:

只是回答你问题的最后一部分......

我也见过Thread.currentThread().interrupted()。这是正确的使用方法,还是Thread.interrupted() 足够?

在纯粹的功能术语中,它们的含义完全相同。

但就可读性而言,

    Thread.currentThread().interrupted()

使它看起来就像你在调用一个实例方法......但你不是。因此,

    Thread.interrupted()

更好。当然不要这样做:

    Thread someThread = ...
    someThread.interrupted()

看起来您正在测试someThread,但您实际上正在测试当前线程。非常误导!

【讨论】:

@sjlee - 我的回答不涉及isInterrupted。请看第一句话。【参考方案3】:

差异非常微妙,通常无关紧要。您显然可以根据需要设置或清除中断标志。甚至没有一个标准的做法是说“使用一个,从不使用另一个”。

主要的一点是要知道你对中断标志做了什么:让它处于你没有特别打算的状态肯定不会产生细微的差别。

永远不要使用Thread.currentThread().interrupted()。这只会产生误导,尤其是如果您有 someOtherThread.interrupted()

【讨论】:

在我正在查看的文档中,interrupted 是静态的,所以不需要将其称为 Thread.currentThread().interrupted() 吗? 这不仅仅是不必要的,但我认为 OP 的问题主要不是关于这种差异。这更像是一个侧面。【参考方案4】:

使用Thread.interrupted()有什么不同(除了使用interrupted()时清除中断标志)?

不,但这是一个非常深刻的区别。如果您只在示例中使用它,在线程的 run 方法中的单个 while 循环内,以便在线程中断时退出 run 方法,那么没有区别,但在其他情况下可能。例如,想象嵌套循环,每个循环都检查中断状态(内部循环在外部循环检查之前清除状态......)

Thread.currentThread().interrupted()Thread.interrupted() 的区别,没有功能上的区别,但是后者更短,所以使用它。

【讨论】:

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

以上是关于为啥在实现 Runnable 时使用 Thread.currentThread().isInterrupted() 而不是 Thread.interrupted()?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要实现Runnable接口,来实现多线程?把Thread作为父类则不能呢?

为啥使用线程池而不使用new Thread(runnable).start();

线程01-Thread类,Runnable接口

线程01-Thread类,Runnable接口

将Thread对象作为Runnable对象使用的结果

Thread使用总结——Runnable和Thread的区别是啥