并发编程(二十七):并发设计模式之优雅的结束线程

优雅的结束线程是指线程T1中去结束线程T2,并且让T2有机会处理结束线程的流程,那么该如何实现呢?

1.两阶段终止模式

两阶段的含义:

  1. 第一阶段:向线程发送终止指令
  2. 第二阶段:响应终止指令

1.1.第一阶段

Java线程进入终止状态的前提是该现在处于Runnable状态,但是此时线程可能处于休眠状态。而Java提供的interrupt方法它可以将休眠状态的线程转换到 RUNNABLE 状态。

1.2.第二阶段

而Runnable接收到指令后,该如何进入终止状态呢?

  1. 异常
  2. 执行完run方法,此时能够设置终止标示位,根据标示位去结束线程的执行

示例代码如下:

设置了自己的终止线程标志位

class Proxy {
  // 线程终止标志位
  volatile boolean terminated = false;
  boolean started = false;
  // 采集线程
  Thread rptThread;
  // 启动采集功能
  synchronized void start(){
    // 不允许同时启动多个采集线程
    if (started) {
      return;
    }
    started = true;
    terminated = false;
    rptThread = new Thread(()->{
      while (!terminated){
        // 省略采集、回传实现
        report();
        // 每隔两秒钟采集、回传一次数据
        try {
          Thread.sleep(2000);
        } catch (InterruptedException e){
          // 重新设置线程中断状态
          Thread.currentThread().interrupt();
        }
      }
      // 执行到此处说明线程马上终止
      started = false;
    });
    rptThread.start();
  }
  // 终止采集功能
  synchronized void stop(){
    // 设置中断标志位
    terminated = true;
    // 中断线程 rptThread
    rptThread.interrupt();
  }
}

为什么需要两阶段终止,我直接检查标志位或者线程的中断状态不可以吗?

两阶段终止模式是一种应用很广泛的并发设计模式,在 Java 语言中使用两阶段终止模式来优雅地终止线程,需要注意两个关键点:一个是仅检查终止标志位是不够的,因为线程的状态可能处于休眠态;另一个是仅检查线程的中断状态也是不够的,因为我们依赖的第三方类库很可能没有正确处理中断异常。

2.如何优雅的终止线程池

线程池提供了两个方法:**shutdown()*和*shutdownNow()

2.1.shutdown()

线程池执行shutdown后,就会拒绝接受新的任务,但是会将线程池中的任务全部执行完

2.2.shutdownNow()

该方法会拒绝接受新的任务,同时还会中断线程池中正在执行的任务,已经进入阻塞队列的任务也被剥夺了执行的机会,不过队列中的这些任务会作为返回值返回。因为该方法中断了线程池中正在执行的任务,所以这些任务需要优雅的结束,接需要正确的处理线程中断

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×