今天在看 ReentrantLock,AbstractQueuedSynchronizer(AQS)时,发现它调用线程的 interrupted 方法后,如果返回 true,则再会调用线程自己的 interrupt 方法,对此不太理解这段代码的意思。网上查询后才发现这是 JAVA 的中断机制。
什么是中断机制?
中断机制是一种协作机制,说白了就是停止一个线程的一种策略,是替代 stop 方法的策略。举个例子,当线程 A 要停止线程 B 时,A 会给 B 一个中断信号,告诉 B :你应该停止运行了,当 A 收到该信号后,A 可以选择在某一时刻以某种方式中断自己(这时才是真正的中断),也可以不理会这个信号继续运行,甚至清除这个信号。需要注意的是 A 线程自己杀死自己,也需要先给自己一个信号。
一般中断机制应用在一个长期运行的一个线程上(比如循环),这个线程会有规律的检测当前中断信号是否为 true,如果是就开始中断操作,中断操作可以是退出循环,继续运行剩下的代码,也可以是立即 return等,这个就由开发者自己来控制了。
说到这里你可能会意识到,如果只是一个信号的话,那我们自己定义一个信号可以吗?答案当然是可以,只是,JDK 已经帮我们做了,那我们就不必多此一举了。
Thread 的中断操作
操作 | 方法描述 | 说明 |
---|---|---|
interrupt | 实例方法 | 给指定线程一个中断信号。如果当前线程因为 Object.wait,Thread.join,Thread.sleep 而阻塞,此时调用该方法则中断信号会被清除并且抛出 InterruptedException 异常。如果反过来线程已经有中断信号,然后再调用以上方法,也会清除信号并抛出 InterruptedException 异常。 对于 LockSupport.park 线程都会取消阻塞,不会抛出异常且不会改变信号。 |
interrupted | 静态方法 | 返回旧信号,并且清除信号 |
isInterrupted | 实例本地方法 | 仅返回信号 |
着重看下 interrupt 方法,源码:
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);//这一步就说明,如果你设置了 Interruptible 则,则会按照你定义的中止逻辑中止操作
return;
}
}
interrupt0();
}
为什么会出现中断机制?
在之前的 JDK 版本中其实有强制停止线程的方法 Thread.stop(但 jDK8 中已经废弃(什么时候废弃的也没说明)),Thread.stop 会立即杀死线程,这会导致对象数据不一致,引发一系列意想不到的问题,所以已经废弃。推荐使用上面的方法。
既然说到了中断机制那就再说下 subpend 和 resume 吧。这两个方法也已经被废弃,因为它们d本质上是容易死锁的。官方给出的替代方法和 stop 方法一样,给出信号,使用 wait 和 notify 替代。
其实官方都有说明:https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html