Java:Thread.interrupted()和Thread.isInterrupted()之间的使用差异?

pyt*_*ude 54 java multithreading

Java问题:据我所知,有两种方法可以检查线程内部线程是否接收到中断信号,Thread.interrupted()并且Thread.isInterrupted()它们之间的唯一区别是前者重置内部中断标志.

到目前为止,我一直使用Thread.isInterrupted(),从来没有遇到任何问题.然后,我见过的大多数教程都推荐使用Thread.interrupted().这有什么具体原因吗?

Mic*_*ers 81

interrupted()static并检查当前线程.isInterrupted()是一个实例方法,它检查Thread调用它的对象.

常见错误是在实例上调用静态方法.

Thread myThread = ...;
if (myThread.interrupted()) {} // WRONG! This might not be checking myThread.
if (myThread.isInterrupted()) {} // Right!
Run Code Online (Sandbox Code Playgroud)

另一个区别是,interrupted()还会清除当前线程的状态.换句话说,如果你连续两次调用它并且线程没有在两次调用之间中断,那么false即使第一次调用返回,第二次调用也会返回true.

Javadoc中告诉你,这样重要的事情; 经常使用它们!

  • `另一个区别是interrupt()也会清除当前线程的状态.[这会使*中断()*用词不当](https://www.youtube.com/watch?v=aAb7hSCtvGw#t=2909) (7认同)

Ano*_*on. 34

如果你使用interrupted,你问的是"自从我上次询问以来我是否被打断了?"

isInterrupted 告诉您调用它的线程当前是否被中断.


eri*_*son 7

interrupted()方法是一种类方法,它始终检查当前线程清除中断"标志".换句话说,第二次调用interrupted()将返回false.

isInterrupted()方法是一种实例方法; 它报告调用它的线程的状态.此外,它不会清除中断标志.如果设置了该标志,则在调用此方法后它将保持设置状态.


Jes*_*ick 6

周围有许多习语InterruptedException,但问题是关于明确检查中断状态.

我的理解是isInterrupted(实例方法)应该很少使用 - 主要用于日志记录和调试等.它只给出了给定线程上的标志的快照,这可能很快就会过时.

正常的习惯用法是检查interrupted(静态方法),如果你正在编写一个你想要在某个点被取消的任务,它不会InterruptedException因为睡眠或阻塞I/O调用等调用抛出的东西.如果您看到标志设置,您应该尽可能快地停止当前计算,提前返回或抛出异常(可能InterruptedException).

举个例子,如果你的任务看起来像

void process(Things[] things) throws InterruptedException {
    for (Thing thing : things) {
        thing.twiddle(); // this call throws InterruptedException
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你不需要做任何其他事情; 如果有人打电话Thread.interrupt给你的线程,在当前或下一次twiddle通话期间,InterruptedException将会抛出并停止你的任务.

但是,如果twiddleInterruptedException,一般不能在中途被打断?假设每个这样的呼叫需要100毫秒,但things.length可能是100.然后process即使有人试图中断它也可能被阻止10秒,这在您的应用程序中可能是不可接受的.所以你可以明确检查中断:

void process(Things[] things) {
    if (Thread.interrupted()) {
        return;
    }
    for (Thing thing : things) {
        thing.twiddle();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里你可以看到为什么重要的是interrupted原子地检查和清除标志:你用它来确认收到一条消息,有人礼貌地要求你尽快停止.(在这种情况下,在请求的大约100ms内.)您还可以看到为什么这必须是一个静态方法,在当前线程上运行:它只在检查是否应该停止周围代码的上下文中才有意义.

当然,如果调用者process假设它已经完成,那么简单地return按这里所示将会产生误导.因此,您可能希望process返回已完成处理的事物的数量,或者可能更适合抛出异常:

void process(Things[] things) throws InterruptedException {
    if (Thread.interrupted()) {
        throw new InterruptedException();
    }
    for (Thing thing : things) {
        thing.twiddle();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,调用者获得(已检查)异常,通知他们其他人要求在中间停止处理.通常调用者应该让异常抛出调用堆栈.

如果您无法停止当前任务但又需要知道停止它的请求确实进入,例如为了缩短剩下的工作时间,您也可以重新打破自己:

void process(Things[] things) {
    boolean twiddleFully = true;
    if (twiddleFully && Thread.interrupted()) {
        twiddleFully = false;
        Thread.currentThread().interrupt();
    }
    for (Thing thing : things) {
        thing.twiddle(twiddleFully);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们可以更快地处理剩余的事情,但仍然完成循环,并重新打开中断的标志,以便我们的调用者可以决定处理它.


Dea*_*vey 5

Java 中的线程中断是建议性的。如果您调用 Thread.interrupt(),那么它将设置标志并取消任何未完成的 IO 任务(这将抛出 InterruptedException)。然而,这取决于在线程中执行的代码来处理这个问题。这样做称为实现线程中断策略。

然而,由于线程的中断状态是共享的,因此任何此类处理都是线程安全的,这一点很重要。如果您正在处理它,您不希望其他一些线程关闭并尝试对中断标志执行某些操作。由于这个原因,Thread.interrupted() 标志使这个原子化,所以当你想说:“如果这个线程被中断,那么我将处理它。通常这将涉及清理一些资源。一旦你完成后,您可能应该传播中断标志,以便调用者可以处理它。您可以通过再次调用 Thread.interrupt 来做到这一点。