目录
两阶段终止模式(Two Phase Termination)
interrupt
打断阻塞
阻塞状态:处于阻塞状态的线程,线程调度器是不会主动让此线程使用时间片的。
能够使线程进入阻塞状态的方法有 sleep wait join.
注意:
- 打断正在睡眠的线程后,线程的打断标记并不会置为true,而是false。
- 被打断的睡眠的线程并不全是直接使用cpu时间片,仍然是处于就绪状态,还是要排队滴!
打断正常
开门见山,上案例。
如图所示,我们将t1线程进行打断,运行结果为:
所以由结果可知:正常的线程在被打断时是不会停止继续占用cpu时间片的,而是改变此线程的打断标记为true。 所以打断正常线程就相当于通知该线程有人要让你停下来,而不是强制让你停下来,非常的人性化!
如果真的想要做到 interrupt即停止,那么我们的打断标记就发挥作用了。
我们知道在打断正常线程的动作中,会使打断标记置为true,所以我们可以根据该boolen类型的值来进行判断是否打断,从而来决定线程是否进行打断(手动打断)。
代码如下:
结果如下:
两阶段终止模式(Two Phase Termination)
在一个线程T1中如何优雅的终止线程T2? 这里的优雅是指给T2一个料理后事的机会。
提到终止线程,那么首先想到的就是暴力停止,就像我们电脑卡死,直接关机一样。但是在线程中暴力杀死线程可是会有大麻烦的。
错误思路
- 暴力stop()方法停止线程
stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其他线程将永远无法获得锁
- 使用System.exit(int)方法停止线程
目的是停止一个线程,但该做法却会让整个程序都停止,比stop还离谱。
所以这两种方法时一定要摒弃的。
两阶段终止模式 - interrupt分析
流程如下:
- while 判断该线程的打断标记是否为true,如果为true,则说明该线程需要被停止。那么就通知该线程,去料理后事吧,然后就可以结束循环了。
- 如果打断标记false,那么就代表在监控时刻该线程并没有被命令停止,那么就呼吸式监控(睡眠单位时间,然后再看看有没有抛出InterruptedException)。
- 如果没有抛出异常,就再返回我们的第一步while 循环判断;如果抛出了异常,就说明,真的给我们的线程下了死亡通牒,所以现在就需要下达死亡通知书了,把打断标记置为true,然后再进行whlie循环判断,料理后事。
两阶段终止模式代码实现
@Slf4j(topic = "c.demo4")
public class demo4 {
public static void main(String[] args) throws InterruptedException {
TwoPhaseTermination tpt = new TwoPhaseTermination();
tpt.start();
Thread.sleep(5000);
tpt.stop();
}
}
@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination {
private Thread monitor;
// 启动监控线程
public void start() {
monitor = new Thread(() -> {
while (true) {
Thread thread = Thread.currentThread();
if (thread.isInterrupted()) {
log.debug("料理后事");
break;
}
try {
sleep(1000);
log.debug("执行监控记录");
} catch (InterruptedException e) {
e.printStackTrace();
// 重新设置打断标记
thread.interrupt();
}
}
});
monitor.start();
}
public void stop() {
monitor.interrupt();
}
}
Interrupt打断park
park方法并不是Thread提供的方法,而是LockSupport(锁支持)类提供的方法。
当处于park状态的线程,如果被interrupt打断,会将打断标记置为true。
注意:在处于park的线程被打断后就无法再自动执行park方法。
因为该线程的打断标记已经被置为true,如果还想让改行程继续执行park方法,就需要手动重置该线程的打断标记为false。