死磕 java线程系列之线程池深入解析——生命周期
(手机横屏看源码更方便)
注:java源码分析部分如无特殊说明均基于 java8 版本。
注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类。
简介
上一章我们一起重温了下线程的生命周期(六种状态还记得不?),但是你知不知道其实线程池也是有生命周期的呢?!
问题
(1)线程池的状态有哪些?
(2)各种状态下对于任务队列中的任务有何影响?
先上源码
其实,在我们讲线程池体系结构的时候,讲了一些方法,比如shutDown()/shutDownNow(),它们都是与线程池的生命周期相关联的。
我们先来看一下线程池ThreadPoolExecutor中定义的生命周期中的状态及相关方法:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; // =29 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // =000 11111... // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; // 111 00000... private static final int SHUTDOWN = 0 << COUNT_BITS; // 000 00000... private static final int STOP = 1 << COUNT_BITS; // 001 00000... private static final int TIDYING = 2 << COUNT_BITS; // 010 00000... private static final int TERMINATED = 3 << COUNT_BITS; // 011 00000... // 线程池的状态 private static int runStateOf(int c) { return c & ~CAPACITY; } // 线程池中工作线程的数量 private static int workerCountOf(int c) { return c & CAPACITY; } // 计算ctl的值,等于运行状态“加上”线程数量 private static int ctlOf(int rs, int wc) { return 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()钩子方法;