死磕java线程系列之线程池深入解析——生命周期

  

注:java源码分析部分如无特殊说明均基于java8版本。

注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类。

简介

上一章我们一起重温了下线程的生命周期(六种状态还记得不?),但是你知不知道其实线程池也是有生命周期的呢? !

问题

(1)线程池的状态有哪些?

(2)各种状态下对于任务队列中的任务有何影响?

先上源码

其实,在我们讲线程池体系结构的时候,讲了一些方法,比如关闭()/shutDownNow(),它们都是与线程池的生命周期相关联的。

我们先来看一下线程池ThreadPoolExecutor中定义的生命周期中的状态及相关方法:

<>以前私人最终AtomicInteger ctl=new AtomicInteger (ctlOf(跑步,0));私有静态最终int COUNT_BITS=整数。大小- 3;//=29私有静态最终int能力=(1,lt;, lt;COUNT_BITS) - 1;//=000 11111……//runState存储在高阶bitsprivate静态最终int运行=1,lt;, lt;COUNT_BITS;//111 00000…私有静态最终int关闭=0,lt;, lt;COUNT_BITS;//000 00000…私有静态最终int停止=1,lt;, lt;COUNT_BITS;//001 00000…私有静态最终int整理=2,lt;, lt;COUNT_BITS;//010 00000…私有静态最终int终止=3,lt;, lt;COUNT_BITS;//011 00000…//线程池的状态私有静态int runStateOf (int c){返回c, amp;~能力;}//线程池中工作线程的数量私有静态int workerCountOf (int c){返回c, amp;能力;}//计算ctl的值,等于运行状态”加上“线程数量私有静态int ctlOf (int rs, int wc){返回rs | wc;}

从上面这段代码,我们可以得出:

(1)线程池的状态和工作线程的数量共同保存在控制变量ctl中,类似于AQS中的state变量,不过这里是直接使用的AtomicInteger,这里换成unsafe+volatile也是可以的;

(2)ctl的高三位保存运行状态,低29位保存工作线程的数量,也就是说线程的数量最多只能有(2^29-1)个,也就是上面的CAPACITY;

(3)线程池的状态一共有五种,分别是RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED;

(4)RUNNING,表示可接受新任务,且可执行队列中的任务;

(5)SHUTDOWN,表示不接受新任务,但可执行队列中的任务;

(6)STOP,表示不接受新任务,且不再执行队列中的任务,且中断正在执行的任务;

(7)TIDYING,所有任务已经中止,且工作线程数量为0,最后变迁到这个状态的线程将要执行terminated()钩子方法,只会有一个线程执行这个方法;

(8)TERMINATED,中止状态,已经执行完terminated()钩子方法;

流程图

下面我们再来看看这些状态之间是怎么流转的:

死磕 java线程系列之线程池深入解析——生命周期

(1)新建线程池时,它的初始状态为RUNNING,这个在上面定义ctl的时候可以看到;

(2)RUNNING->SHUTDOWN,执行shutdown()方法时;

(3)RUNNING->STOP,执行shutdownNow()方法时;

(4)SHUTDOWN->STOP,执行shutdownNow()方法时【本文由公从号“彤哥读源码”原创】;

(5)STOP->TIDYING,执行了shutdown()或者shutdownNow()后,所有任务已中止,且工作线程数量为0时,此时会执行terminated()方法;

(6)TIDYING->TERMINATED,执行完terminated()方法后;

源码分析

你以为贴个状态的源码,画个图就结束了嘛?那肯定不能啊,下面让我们一起来看看源码中是怎么控制的。

(1)RUNNING

RUNNING,比较简单,创建线程池的时候就会初始化ctl,而ctl初始化为RUNNING状态,所以线程池的初始状态就为RUNNING状态。

//初始状态为RUNNINGprivate final AtomicInteger ctl=new AtomicInteger(ctlOf(RUNNING, 0));

(2)SHUTDOWN

执行shutdown()方法时把状态修改为SHUTDOWN,这里肯定会成功,因为advanceRunState()方法中是个自旋,不成功不会退出。

public void shutdown() {    final ReentrantLock mainLock=this.mainLock;
  mainLock.lock ();尝试{
  checkShutdownAccess ();//修改状态为关闭
  advanceRunState(关闭);//标记空闲线程为中断状态
  interruptIdleWorkers ();
  onShutdown ();
  最后}{
  mainLock.unlock ();
  }
  tryTerminate ();
  }私人空advanceRunState (int targetState) {(;;) {int c=ctl.get ();//如果状态大于关闭,或者修改为关闭成功了,才会打破跳出自旋
  如果(runStateAtLeast (c, targetState) | |
  ctl.compareAndSet (c, ctlOf (targetState workerCountOf (c))))休息;
  }
  }

(3)停止

执行shutdownNow()方法时,会把线程池状态修改为停止状态,同时标记所有线程为中断状态。

公共ListshutdownNow () {
  List

死磕java线程系列之线程池深入解析——生命周期