Java:使用Thread.interrupted()和Thread.isInterrupted()之间的区别?
Java的问题:据我所知,有两种方法来检查一个线程内部线程是否收到一个中断信号,Thread.interrupted()和Thread.isInterrupted(),它们唯一的区别是前者重置内部中断的国旗。
到目前为止,我一直使用Thread.isInterrupted(),从来没有任何问题。 再次,我见过的大多数教程推荐使用Thread.interrupted()。 有什么具体的原因吗?
interrupted()
是static
并检查当前线程。 isInterrupted()
是一个实例方法,它检查被调用的Thread
对象。
常见的错误是在实例上调用静态方法。
Thread myThread = ...; if (myThread.interrupted()) {} // WRONG! This might not be checking myThread. if (myThread.isInterrupted()) {} // Right!
另一个区别是, interrupted()
也会清除当前线程的状态。 换句话说,如果你连续调用两次,并且两个调用之间的线程没有中断,那么即使第一个调用返回true
,第二个调用也将返回false
。
Javadocs告诉你这样的重要事情; 经常使用它们!
如果你使用interrupted
,你问的是“自从我上次问起,我被打断了吗?
isInterrupted
告诉你你调用的线程是否当前被中断。
interrupted()
方法是一个总是检查当前线程并清除中断“标志”的类方法。 换句话说,第二次调用interrupted()
将返回false
。
isInterrupted()
方法是一个实例方法; 它会报告被调用的线程的状态。 此外,它不清除中断标志。 如果该标志被设置,在调用此方法后它将保持设置状态。
以下是一些如何使用这些方法的例子:
-
如果您正在编写自己的线程池,则可能需要检查正在pipe理的其中一个线程的中断状态。 在这种情况下,你会调用
managedThread.isInterrupted()
来检查它的中断状态。 -
如果您正在编写自己的InterruptedException处理程序,它不会立即通过
Thread.currentThread().interrupt()
(例如,在exception处理程序之后可能有一个finally块Thread.currentThread().interrupt()
触发相同的exception,您可能需要检查当前正在运行的线程已经通过外部调用或InterruptedException中断。 在这种情况下,您将检查Thread.interrupted()
的布尔值来检查当前线程的状态。
第二种方法对于我来说真的只对我有用,在这种情况下,我恐怕有人写了一个更低层次的exception吞噬者,而且最终还是吃掉了InterruptedException。
Java中的线程中断是build议性的。 如果调用Thread.interrupt(),那么它将设置标志并取消所有未完成的IO任务(这将抛出InterruptedException)。 然而,这取决于在线程中执行的代码来处理这个问题。 这样做被称为实施线程中断策略。
但是因为线程的中断状态是共享的,所以任何这种处理都是线程安全的。 如果您正在处理中断标志,您不希望其他线程closures并试图执行某些操作。 因为这个原因,Thread.interrupted()标志使得它是primefaces的,所以当你想说:“如果这个线程被中断了,那么我将要处理它”),通常这将涉及清理一些资源。你可能应该传播中断的标志,以便呼叫者可以处理它。你可以通过调用Thread.interrupt来完成这个操作。
InterruptedException
有很多成语,但问题是显式检查中断状态。
我的理解是isInterrupted
(实例方法)应该很less使用 – 主要用于日志logging和debugging等。 它只给出给定线程上的标志的快照,之后很快就会过时。
正常的习惯用法是检查interrupted
(静态方法),如果你正在编写一个你想要在某个不被调用的事件时被取消的任务,那么这个任务会因为睡眠或者阻塞I / O调用等而抛出InterruptedException
。 如果看到标志设置,应该尽可能快地停止当前的计算,尽早返回或抛出exception(可能是InterruptedException
)。
举个例子,如果你的任务看起来像这样
void process(Things[] things) throws InterruptedException { for (Thing thing : things) { thing.twiddle(); // this call throws InterruptedException } }
那么你不需要做任何事情; 如果有人在你的线程上调用了Thread.interrupt
,在当前或下一个twiddle
调用期间,一个InterruptedException
将被抛出并停止你的任务。
但是,如果twiddle
不抛出InterruptedException
并且一般不能在中间中断? 说每个这样的调用需要100ms,但是things.length
可能是100.然后,即使有人试图中断它, process
也可能被阻塞10秒,这在你的应用程序中可能是不可接受的。 所以你可以明确地检查中断:
void process(Things[] things) { if (Thread.interrupted()) { return; } for (Thing thing : things) { thing.twiddle(); } }
在这里,你可以看到为什么interrupted
自动检查和清除标志是重要的:你正在使用它来确认收到的消息,有人礼貌地要求你尽快停止。 (在这种情况下,在请求的大约100ms内)。你也可以看到为什么它必须是一个在当前线程上运行的静态方法:它只有在检查周围代码是否应该停止的情况下才有意义。
当然,如果process
的调用者假设它已经完成,那么只要按照这里所示的方式return
就会有误导性。 所以你可能想让process
返回已完成处理的事情的数量,或者可能更适合抛出exception:
void process(Things[] things) throws InterruptedException { if (Thread.interrupted()) { throw new InterruptedException(); } for (Thing thing : things) { thing.twiddle(); } }
在这种情况下,调用者得到(检查)exception,通知他们有人要求在中间停止处理。 通常调用者应该让exception抛出调用堆栈。
如果您无法停止当前的任务,但是仍然需要知道阻止它的请求,您也可以重新打开自己,例如简化其余的工作:
void process(Things[] things) { boolean twiddleFully = true; if (twiddleFully && Thread.interrupted()) { twiddleFully = false; Thread.currentThread().interrupt(); } for (Thing thing : things) { thing.twiddle(twiddleFully); } }
在这里,我们可以更快地处理剩下的事情,但仍然完成循环,并打开中断标志,以便我们的调用者可以决定处理它。
中断()方法是类线程的静态方法检查当前线程并清除中断“标志”.ie第二次调用中断()将返回false。
isInterrupted()方法是一个实例方法; 它会报告被调用的线程的状态。 它不清除中断标志。
如果该标志被设置,在调用此方法后它将保持设置状态。
Thread myThread = ...; if (myThread.interrupted()) {} //error Thread.interrupted()//right if (myThread.isInterrupted()) {} // Right
这是一个古老的问题,经历了答案,我觉得还有一些缺失的信息。 这是我试图填补这一缺失的信息。
从Java 5开始,通常只会间接处理线程。事实上,java.util.Executor框架中产生的线程是在库方法中处理的。 这些线程通常会调用像Future.get()
那样阻塞自然的实体。 即get()
块直到结果是可用的。现在有一个get()
的重载forms,它需要一个超时值并调用该方法意味着该线程想要等待get ()
返回的超时时间一个值,如果不是那个任务可以通过Future.cancel()取消。 所以这些方法严重处理中断,一旦他们嗅探到一个中断,他们也抛出检查InterruptionException。 因此调用者被迫处理InterruptionException。 由于它们已经传播了传递中断状态的InterruptedException,所以阻塞方法通过调用Thread.interrupt()来清除中断状态也是有意义的。 否则,违反了InterruptedException的合约。
但是,如果您正在处理当前尚未推荐的原始线程,则在调用静态方法interrupted()
时应该小心,因为如果连续调用两次并且线程在两次调用之间不中断,则第二个即使第一次调用返回true,调用也将返回false。