在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。
1. 错误思路
- 使用线程对象的 stop() 方法停止线程
stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,
其它线程将永远无法获取锁
- 使用 System.exit(int) 方法停止线程
目的仅是停止一个线程,但这种做法会让整个程序都停止
2. 两阶段终止模式
利用 isInterrupted
interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行
class TPTInterrupt {private Thread thread; //监控线程//启动监控线程public void start(){thread = new Thread(() -> {while(true) {Thread current = Thread.currentThread();if(current.isInterrupted()) {log.debug("料理后事");break;}try {Thread.sleep(1000);log.debug("执行业务操作。。。");} catch (InterruptedException e) {current.interrupt();}}},"监控线程");thread.start();}//停止监控线程public void stop() {thread.interrupt();}}
调用
TPTInterrupt t = new TPTInterrupt();t.start();Thread.sleep(3500);log.debug("stop");t.stop();
结果
11:49:42.915 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。11:49:43.919 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。11:49:44.919 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。11:49:45.413 c.TestTwoPhaseTermination [main] - stop11:49:45.413 c.TwoPhaseTermination [监控线程] - 料理后事
利用volatile修饰的停止标记
// 停止标记用 volatile 是为了保证该变量在多个线程之间的可见性// 我们的例子中,即主线程把它修改为 true 对 t1 线程可见class TPTVolatile {private Thread thread;private volatile boolean stop = false;public void start(){thread = new Thread(() -> {while(true) {Thread current = Thread.currentThread();if(stop) {log.debug("料理后事");break;}try {Thread.sleep(1000);log.debug("将结果保存");} catch (InterruptedException e) {}}},"监控线程");thread.start();}public void stop() {stop = true;thread.interrupt();}}
调用
TPTVolatile t = new TPTVolatile();t.start();Thread.sleep(3500);log.debug("stop");t.stop();
结果
11:54:52.003 c.TPTVolatile [监控线程] - 将结果保存11:54:53.006 c.TPTVolatile [监控线程] - 将结果保存11:54:54.007 c.TPTVolatile [监控线程] - 将结果保存11:54:54.502 c.TestTwoPhaseTermination [main] - stop11:54:54.502 c.TPTVolatile [监控线程] - 料理后事
