02小节:深度解析线程池底层原理
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
深度解析线程池底层原理,元数据信息:
- 什么是线程池oneThread:https://t.zsxq.com/5GfrN
- 代码仓库:https://gitcode.net/nageoffer/onethread —— 申请项目权限参考上述线程池项目链接
- 章节难度:★★☆☆☆ - 中等
- 视频地址:本章节内容简单,无
©版权所有 - 拿个offer-开源&项目实战星球专属学习项目,依据《中华人民共和国著作权法实施条例》和《知识星球产权保护》,严禁未经本项目原作者明确书面授权擅自分享至 GitHub、Gitee 等任何开放平台。违者将面临法律追究。
内容摘要:线程池通过复用线程、管理任务队列与智能调度策略,大幅提升系统吞吐并降低资源消耗。其核心在于ThreadPoolExecutor的三大组件:工作线程(Worker)实现任务执行与复用,阻塞队列缓冲任务洪峰,位运算变量(ctl)统一管控状态与线程数。这种设计完美平衡了响应速度与资源利用率,是高并发场景的底层基石。本篇文章跟着马哥一起看下线程池底层设计之美。
课程目录如下所示:
- 线程池介绍
- 线程池概要
- 状态控制
- 线程池状态
- 任务调度
- 文末总结
线程池介绍
通常当我们提到“线程池”时,狭义上指的是 ThreadPoolExectutor 及其子类,而广义上则指整个 Executor 大家族:

Executor:整个体系的最上级接口,定义了 execute 方法。ExecutorService:它在Executor接口的基础上,定义了 submit、shutdown 与 shutdownNow 等方法,完善了对 Future 接口的支持。AbstractExecutorService:实现了ExecutorService中关于任务提交的方法,将这部分逻辑统一为基于 execute 方法完成,使得实现类只需要关系 execute 方法的实现逻辑即可。ThreadPoolExecutor:线程池实现类,完善了线程状态管理与任务调度等具体的逻辑,实现了上述所有的接口。
ThreadPoolExecutor 作为 Executor 体系下最通用的实现基本可以满足日常的大部分需求,不过实际上也有不少定制的扩展实现,比如:
- JDK 基于
ThreadPoolExecutor实现了ScheduledThreadPoolExecutor用于支持任务调度。 - Tomcat 基于
ThreadPoolExecutor实现了一个同名的线程池,用于处理 Web 请求。 - Spring 基于
ExecutorService接口提供了一个ThreadPoolTaskExecutor实现,它仍然基于内置的ThreadPoolExecutor运行,在这个基础上提供了不少便捷的方法。
ThreadPoolExecutor 基于生产者与消费者模型实现,从功能上可以分为三个部分:
- 线程池本体:负责维护运行状态、管理工作线程以及调度任务。
- 工作队列:即在构造函数中指定的阻塞队列,它扮演者生产者消费者模型中缓冲区的角色。工作线程将会不断的 从队列中获取并执行任务。
- 工作线程:即持有
Thread对象的内部类Worker,当一个Wroker被创建并启动以后,它将会不断的从工作队列中获取并执行任务,直到它因为获取任务超时、任务执行异常或线程池停机后才会终止运行。
当我们向线程池提交任务时,线程池将根据下述逻辑处理任务:
- 如果当前工作线程数小于核心线程数,则启动一个工作线程执行任务。
- 如果当前工作线程数大于等于核心线程数,且阻塞队列未满,则将任务添加到阻塞队列。
- 如果当前工作线程数大于等于核心线程数,且阻塞队列已满,则启动一个工作线程执行任务。
- 如果当前工作线程数已达最大值,且阻塞队列已满,则触发拒绝策略。

而当一个工作线程启动以后,它将会在一个 while 循环中重复执行下述逻辑:
- 通过
getTask方法从工作队列中获取任务,如果拿不到任务就阻塞一段时间,直到超时或者获取到任务。如果成功获取到任务就进入下一步,否则就直接进入线程退出流程; - 调用
Worker的lock方法加锁,保证一个线程只被一个任务占用; - 调用
beforeExecute回调方法,随后开始执行任务,如果在执行任务的过程中发生异常则会被捕获; - 任务执行完毕或者因为异常中断,此后调用一次
afterExecute回调方法,然后调用unlock方法解锁; - 如果线程是因为异常中断,那么进入线程退出流程,否则回到步骤 1 进入下一次循环。

线程池概要
1. 构造函数的参数
ThreadPoolExecutor 类一共提供了四个构造方法,我们基于参数最完整构造方法了解一下线程池创建所需要的变量:
public ThreadPoolExecutor(int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 非核心线程闲置存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 创建线程使用的线程工厂
RejectedExecutionHandler handler // 拒绝策略) {
}
- 核心线程数:即长期存在的线程数,当线程池中运行线程未达到核心线程数时会优先创建新线程**。**
- 最大线程数:当核心线程已满,工作队列已满,同时线程池中线程总数未超过最大线程数,会创建非核心线程。
- 超时时间:非核心线程闲置存活时间,当非核心线程闲置的时的最大存活时间。
- 时间单位:非核心线程闲置存活时间的时间单位。
- 任务队列:当核心线程满后,任务会优先加入工作队列,等待核心线程消费。
- 线程工厂:线程池创建新线程时使用的线程工厂。
- 拒绝策略:当工作队列已满,且线程池中线程数已经达到最大线程数时,执行的兜底策略。
线程池每个参数的作用算是一个老生常谈的问题了,这里我们不过多赘述,你只需大概了解这几个参数即可,在下文我们会结合源码和具体的场景进一步的带你了解他们具体含义。