在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。
1. 错误思路

  • 使用线程对象的 stop() 方法停止线程

stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,
其它线程将永远无法获取锁

  • 使用 System.exit(int) 方法停止线程

目的仅是停止一个线程,但这种做法会让整个程序都停止
2. 两阶段终止模式
image.png

利用 isInterrupted

interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行

  1. class TPTInterrupt {
  2. private Thread thread; //监控线程
  3. //启动监控线程
  4. public void start(){
  5. thread = new Thread(() -> {
  6. while(true) {
  7. Thread current = Thread.currentThread();
  8. if(current.isInterrupted()) {
  9. log.debug("料理后事");
  10. break;
  11. }
  12. try {
  13. Thread.sleep(1000);
  14. log.debug("执行业务操作。。。");
  15. } catch (InterruptedException e) {
  16. current.interrupt();
  17. }
  18. }
  19. },"监控线程");
  20. thread.start();
  21. }
  22. //停止监控线程
  23. public void stop() {
  24. thread.interrupt();
  25. }
  26. }

调用

  1. TPTInterrupt t = new TPTInterrupt();
  2. t.start();
  3. Thread.sleep(3500);
  4. log.debug("stop");
  5. t.stop();

结果

  1. 11:49:42.915 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。
  2. 11:49:43.919 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。
  3. 11:49:44.919 c.TwoPhaseTermination [监控线程] - 执行业务操作。。。
  4. 11:49:45.413 c.TestTwoPhaseTermination [main] - stop
  5. 11:49:45.413 c.TwoPhaseTermination [监控线程] - 料理后事

利用volatile修饰的停止标记

  1. // 停止标记用 volatile 是为了保证该变量在多个线程之间的可见性
  2. // 我们的例子中,即主线程把它修改为 true 对 t1 线程可见
  3. class TPTVolatile {
  4. private Thread thread;
  5. private volatile boolean stop = false;
  6. public void start(){
  7. thread = new Thread(() -> {
  8. while(true) {
  9. Thread current = Thread.currentThread();
  10. if(stop) {
  11. log.debug("料理后事");
  12. break;
  13. }
  14. try {
  15. Thread.sleep(1000);
  16. log.debug("将结果保存");
  17. } catch (InterruptedException e) {
  18. }
  19. }
  20. },"监控线程");
  21. thread.start();
  22. }
  23. public void stop() {
  24. stop = true;
  25. thread.interrupt();
  26. }
  27. }

调用

  1. TPTVolatile t = new TPTVolatile();
  2. t.start();
  3. Thread.sleep(3500);
  4. log.debug("stop");
  5. t.stop();

结果

  1. 11:54:52.003 c.TPTVolatile [监控线程] - 将结果保存
  2. 11:54:53.006 c.TPTVolatile [监控线程] - 将结果保存
  3. 11:54:54.007 c.TPTVolatile [监控线程] - 将结果保存
  4. 11:54:54.502 c.TestTwoPhaseTermination [main] - stop
  5. 11:54:54.502 c.TPTVolatile [监控线程] - 料理后事