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中告诉你,这样重要的事情; 经常使用它们!
该interrupted()
方法是一种类方法,它始终检查当前线程并清除中断"标志".换句话说,第二次调用interrupted()
将返回false
.
该isInterrupted()
方法是一种实例方法; 它报告调用它的线程的状态.此外,它不会清除中断标志.如果设置了该标志,则在调用此方法后它将保持设置状态.
周围有许多习语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
将会抛出并停止你的任务.
但是,如果twiddle
不不扔InterruptedException
,一般不能在中途被打断?假设每个这样的呼叫需要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)
在这里,我们可以更快地处理剩余的事情,但仍然完成循环,并重新打开中断的标志,以便我们的调用者可以决定处理它.
Java 中的线程中断是建议性的。如果您调用 Thread.interrupt(),那么它将设置标志并取消任何未完成的 IO 任务(这将抛出 InterruptedException)。然而,这取决于在线程中执行的代码来处理这个问题。这样做称为实现线程中断策略。
然而,由于线程的中断状态是共享的,因此任何此类处理都是线程安全的,这一点很重要。如果您正在处理它,您不希望其他一些线程关闭并尝试对中断标志执行某些操作。由于这个原因,Thread.interrupted() 标志使这个原子化,所以当你想说:“如果这个线程被中断,那么我将处理它。通常这将涉及清理一些资源。一旦你完成后,您可能应该传播中断标志,以便调用者可以处理它。您可以通过再次调用 Thread.interrupt 来做到这一点。