两阶段终止

在一个线程 T1 中如何“优雅”终止线程 T2?这里的优雅指的是给 T2 一个料理后事的机会,T2能够完成自己的任务。

错误思路

  1. 使用线程对象的 stop() 方法停止线程
    1. stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
  1. 使用 System.exit(int) 方法停止线程目的仅是停止一个线程,但这种做法会让整个程序都停止

利用打断标记 : isInterrupted实现

 
notion image
@Slf4j(topic = "c.TestTwoPhaseTermination") public class TestTwoPhaseTermination { public static void main(String[] args) throws InterruptedException { TPTInterrupt t = new TPTInterrupt(); t.start(); Thread.sleep(3500); log.debug("stop"); t.stop(); } } @Slf4j(topic = "c.TPTInterrupt") 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(); } }
输出
17:03:13.627 c.TPTInterrupt [监控线程] - 将结果保存 17:03:14.640 c.TPTInterrupt [监控线程] - 将结果保存 17:03:15.649 c.TPTInterrupt [监控线程] - 将结果保存 17:03:16.123 c.TestTwoPhaseTermination [main] - stop 17:03:16.123 c.TPTInterrupt [监控线程] - 料理后事
@Slf4j(topic = "c.TPTVolatile") 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(); } }

利用停止标记 : volatile实现

@Slf4j(topic = "c.TPTVolatile") 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();
结果
15:46:41.204 c.TPTVolatile [监控线程] - 将结果保存 15:46:42.212 c.TPTVolatile [监控线程] - 将结果保存 15:46:43.216 c.TPTVolatile [监控线程] - 将结果保存 15:46:43.710 c.TestTwoPhaseTermination [main] - stop 15:46:43.710 c.TPTVolatile [监控线程] - 料理后事