中断状态与InterruptedException异常的相互转换

当interrupt方法被调用后,线程就可以被中断了。中断线程这个行为会带来一下结果之一。

(1) 线程变为“中断状态”:反映为“状态”
(2) 抛出“InterruptedException异常”:反映为“控制”

通常情况下会是结果(1);当线程正在sleep、wait、join时会是结果(2)(这时线程不会变为中断状态)。
但是,上面的(1)和(2)是可以相互转换的。即,可以将(1)变为(2),也可以将(2)变为(1)。可以根据程序需要——大多是为了防止代码忘记线程已经被中断的实施——进行转换。

中断状态->InterruptedException异常的转换

可以像下面这样编写代码,以实现“如果线程处于中断状态就抛出异常InterruptedException”。其中的interrupted方法是java.lang.Thread类的静态方法。

1
2
3
if (Thread.interrupted()) {
throw new InterruptedException();
}

将这段if语句写在长时间处理之前可以提高线程对中断的响应性。因为这样可以防止线程因没注意到自己被中断而进入长时间处理的情况发生,

interrupt方法检查的是哪个线程

Thread.interrupt方法会去检查Thread.currentThread()的中断状态。也就是说,无论上面的if语句写在哪个类的哪个方法中,它总是会去检查执行if语句的线程的中断状态。

不想清除中断状态时

当Thread.interrupt方法被调用后,线程将不再处于中断状态。也就是说,一旦调用一次Thread.interrupt方法,中断状态将被清除。
如果想在不清除中断状态的前提下检查当前线程的中断状态,可以使用isInterrupted这个实例方法。

1
2
3
if (Thread.currentThread().isInterrupted()) {
//中断状态下的处理(中断状态不会被清除)
}

InterruptedException异常->中断状态的转换

要想只在指定的时间内让线程停止运行,可以使用Thread.sleep方法。由于Thread.sleep会抛出InterruptedException异常,因此有时会像下面这样编写代码。

1
2
3
4
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}

但是,这样编写代码的话,被抛出的InterruptedException异常将会被忽略。如果某个线程正在sleep时被其他线程中断了,则“已经被中断”这个信息将会遗失。
如果想要防止“已经被中断”这个信息遗失,线程可以像下面这样再次中断自己。

1
2
3
4
5
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

这就相当于将当前捕获到的InterruptedException转换为了中断状态。

InterruptedException异常->InterruptedException异常的转换

还有不将捕获到的InterruptedException异常立即抛出,而是稍后再抛出的方法。

1
2
3
4
5
6
7
8
9
10
11
InterruptedException savedException = null;
...
try {
Thread.sleep(1000)
} catch (InterruptedException e) {
savedException = e;
}
...
if (savedException != null) {
throw savedException;
}

这里,捕获到的InterruptedException异常会先保存在名为savedException的变量中,稍后再被throw出去。