Two-phase Termination(两阶段终止)模式
Q:如何在一个线程中安全的终止另一个线程?
A:使用线程提供的.stop()方法.
如果这时关闭的线程锁住了共享资源,在线程抛出java.lang.ThreadDeath之后终止线程后,即使是在执行synchronized方法的时候,被杀死后就再也没有机会释放锁, 其它线程将永远无法获取锁。
更好的做法是执行完终止处理,再终止线程,即Two-phase Termination,两阶段终止模式
该模式有两个角色:
Terminator: 接收终止指令,进行实际的终止处理。
TerminationRequester: 发起终止指令。
将终止过程分成两个阶段,其中第一个阶段主要是发送终止指令,而第二阶段则是响应终止指令;气利用java线程中断机制的 interrupt()方法,可以让线程从休眠状态转换到RUNNABLE状态。RUNNABLE状态转换到终止状态,优雅的让线程自己执行完run()方法,所以一般采用的方法是设置一个终止标志,然后线程会在合适的时机检查这个终止标志,如果发现符合终止条件,则自动退出 run()方法。
public class ThreadTest {
public static void main(String[] args) {
try {
// 启动线程
TerminateTest t = new TerminateTest();
t.start();
// 执行一段时间
Thread.sleep(5000);
// 发起线程的终止命令
t.terminate();
// 等待线程终止
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class TerminateTest extends Thread {
// 打螺丝
private long num = 0;
// 关闭标志
private volatile boolean shutdownFlag = false;
// 终止请求
public void terminate() {
shutdownFlag = true;
interrupt();
}
// 检查关闭状态
public boolean isShutdown() {
return shutdownFlag;
}
@Override
public void run() {
try {
while (!isShutdown()) {
doWork();
}
} catch (InterruptedException e) {
} finally {
doShutdown();
}
}
// 模拟操作
private void doWork() throws InterruptedException {
num++;
System.out.println(StrUtil.format("工作中: 已打了{}个螺丝.", num));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
// 终止处理
private void doShutdown() {
System.out.println("");
System.out.println("不让干了,就这样吧");
System.out.println(StrUtil.format("法外狂徒今天只打了{}个螺丝.", num));
}
}
}
执行结果如下: