对于Java中 Thread 对象,同一个线程对象调用 start 方法后,会在执行完run 后走向终止(TERMINATED)状态,也就是说一个线程对象是不可以通过多次调用 start 方法重复执行 run 方法内容的。
详情可通过该链接了解:Java同一个线程对象能否多次调用start方法
问题:那 Java 线程池中是如何保证核心线程不会终止的呢?
接下来将通过源码分析线程池是如何保证核心线程不被终止的,在分析前需要了解 ThreadPoolExecutor中几个重要成员变量和方法,便于下面源码阅读:
ThreadPoolExecutor 成员变量和方法介绍
- ctl 原子整型变量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
- ctl 包含两个字段
- workerCount:表示线程池中实际生效的线程数;
- runState:表示线程池运行状态(注意和线程状态进行区分),线程池状态包括以下几种:
- RUNNING:可以接收新任务并可执行队列中的任务;
- SHUTDOWN:不接收新任务,但可执行队列中的任务;
- STOP:不接收新任务,不执行队列任务并且中断正在执行的任务;
- TIDYING:所有任务已终止,workerCount 为0,将会运行钩子方法 terminated;
- TERMINATED:terminated 方法调用完成的状态。
- 线程池中实际生效线程的最大容量
//Integer.SIZE等于32
private static final int COUNT_BITS = Integer.SIZE - 3;
//实际有效线程的最大容量
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
- 实际生效最大线程数为
2 29 − 1 2^{29} - 1 229−1 - 为何使用int类型是因为相对于long运行的更快一点,如果将来int不够用,可以使用AtomicLong代替。
- 线程池运行状态
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
这里我们仅需要知道只有运行(RUNNING)状态是小于0的,其他状态下都是大于等于0的。
4. 获取线程池运行状态
private static int runStateOf(int c) {
return c & ~CAPACITY; }
方法入参 c 即为 ctl,通过该方法位运算可以得到线程池的状态值,并与 3 中的状态进行比较来进行逻辑处理。
5. 获取线程池中当前实际有效的线程数量
private static int workerCountOf(int c) {
return c & CAPACITY; }
同上,方法入参 c 为 ctl 原子整形变量,通过位运算得到线程池中实际的线程数 workCount。
6. 工作线程集合
private final HashSet<Worker> workers = new HashSet<Worker>();
线程池中每一个有效线程都会被包装为 Worker 对象。
7. Worker 内部类
private final class Worker extends AbstractQueuedSynchronizer implements Runnable
- 类 Worker 主要用于维护运行任务线程的中断控制状态;
- 继承 AQS 实现了一个简单的不可重入互斥锁,而不是使用可重入锁,因为不希望工作任务在调用setCorePoolSize之类的池控制方法时能够重新获取锁;
- 为了在线程真正开始运行任务之前禁止中断,将锁状态初始化为负值,并在启动时清除它(runWorker中

最低0.47元/天 解锁文章
170万+

被折叠的 条评论
为什么被折叠?



