从源码角度看Java线程池的运行过程是怎样的?

1 个回答

  • 楚风
    只有行动才能说明一切。
    ## 作用 - 线程池用于统一管理、复用和监控线程,避免为每个任务频繁创建、销毁线程。 - 适合任务数量多、单个任务执行时间较短的场景。 - 主要优势: - 复用线程,降低线程创建和销毁开销; - 任务到达后可以更快执行,提高响应速度; - 统一分配、调优和监控线程,避免无限制创建线程导致资源耗尽。 ## 原理 ### 1. Executor 框架 - `Executor` 是线程池框架的基础接口,定义了执行 `Runnable` 任务的能力。 - `ExecutorService` 继承 `Executor`,定义线程池的主要行为: - `execute(Runnable command)`:执行 `Runnable` 任务; - `submit(task)`:提交 `Runnable` 或 `Callable` 任务,并返回 `Future`; - `shutdown()`:处理完已提交任务后关闭线程池,不再接收新任务; - `shutdownNow()`:尝试停止正在执行的任务并关闭线程池; - `isShutdown()`:判断线程池是否已关闭; - `isTerminated()`:判断所有任务是否已经执行结束。 ### 2. 核心控制字段 ctl 线程池通过一个原子整数 `ctl` 同时保存两类信息: ```java private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; ``` - `ctl` 的高 3 位保存线程池运行状态 `runState`; - 低 29 位保存有效线程数 `workerCount`; - `COUNT_BITS` 为 29; - `CAPACITY` 是线程数量上限,即低 29 位全为 1。 相关方法: ```java private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; } ``` 含义如下: - `runStateOf(c)`:从 `ctl` 中取出线程池状态; - `workerCountOf(c)`:从 `ctl` 中取出当前工作线程数; - `ctlOf(rs, wc)`:将线程池状态和线程数合并成一个 `ctl` 值。 ### 3. 线程池状态 线程池共有 5 种状态: ```java RUNNING = -1 << COUNT_BITS; // 111 SHUTDOWN = 0 << COUNT_BITS; // 000 STOP = 1 << COUNT_BITS; // 001 TIDYING = 2 << COUNT_BITS; // 010 TERMINATED = 3 << COUNT_BITS; // 011 ``` - `RUNNING`: - 线程池初始化后的状态; - 可以接收新任务; - 可以处理阻塞队列中已经提交的任务; - 创建时工作线程数为 0。 - `SHUTDOWN`: - 调用 `shutdown()` 后进入该状态; - 不再接收新任务; - 但会继续处理已经提交的任务。 - `STOP`: - 调用 `shutdownNow()` 后进入该状态; - 不再接收新任务; - 不会继续处理队列中的任务,并尝试中断正在执行的任务。 - `TIDYING`: - 当所有任务已经终止、工作线程数为 0 时进入; - 随后会执行终止钩子方法。 - `TERMINATED`: - 线程池完全终止后的状态。 ### 4. 任务提交流程 从源码设计上看,线程池执行任务时主要围绕核心线程、阻塞队列、最大线程数和拒绝策略进行调度: 1. 任务提交后,如果当前工作线程数小于核心线程数,则尝试创建新的核心线程执行任务。 2. 如果核心线程数已满,则尝试将任务加入阻塞队列。 3. 如果阻塞队列已满,并且当前线程数小于最大线程数,则创建非核心线程执行任务。 4. 如果线程数已经达到最大线程数且队列也无法继续放入任务,则执行拒绝策略。 5. 工作线程执行完当前任务后,会继续从阻塞队列中获取任务,从而实现线程复用。 ### 5. 关闭流程 - 调用 `shutdown()` 后,线程池进入 `SHUTDOWN`: - 拒绝新任务; - 已有任务和队列中的任务仍会继续处理。 - 调用 `shutdownNow()` 后,线程池进入 `STOP`: - 拒绝新任务; - 清空队列中尚未执行的任务; - 尝试中断正在运行的工作线程。 - 当工作线程数归零、任务处理完成后,线程池进入 `TIDYING`,最终转换为 `TERMINATED`。
    发布于 2026-10-25 02:48 •IP属地 广西
    举报
    评论
    收藏