当前位置: 首页 > news >正文

线程池(ThreadPoolExecutor)实现原理和源码细节是Java高并发面试和实战开发的重点


一、线程池核心流程图

+-----------------+
|    提交任务      | submit/execute
+-----------------+|v
+-----------------+
| 判断核心线程数  | < corePoolSize?
+-----------------+|Yes        |Nov           v
[创建新线程]   +-----------------+| 队列是否满?     |+-----------------+|No        |Yesv           v[入队列排队]   +------------------+| 判断最大线程数  |+------------------+|No          |Yesv             v[创建新线程]   [执行拒绝策略]

二、线程池主要环节及源码方法

1. 任务提交(execute/submit)

方法:

  • execute(Runnable command)
  • submit(Runnable/Callable)

源码片段:

public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (!isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);
}

注释速记:

  • 任务先尝试用核心线程处理。
  • 核心线程满则尝试入队列。
  • 队列满则尝试新建非核心线程。
  • 实在不行,执行拒绝策略。

口诀:
先核心,后队列;队列满,再扩容;全满员,拒绝它。


2. 核心线程判断与创建

方法:

  • addWorker(Runnable firstTask, boolean core)

源码片段:

private boolean addWorker(Runnable firstTask, boolean core) {retry:for (;;) {int c = ctl.get();int rs = runStateOf(c);// ...省略状态判断for (;;) {int wc = workerCountOf(c);if (wc >= CAPACITY ||wc >= (core ? corePoolSize : maximumPoolSize))return false;if (compareAndIncrementWorkerCount(c))break retry;c = ctl.get();if (runStateOf(c) != rs)continue retry;}}// ...真正创建Worker线程
}

注释速记:

  • 根据core参数决定是否用核心线程池大小。
  • 用CAS增加线程计数,线程安全。

口诀:
核心先上,CAS抢位,线程安全,才创建。


3. 入队列

方法:

  • workQueue.offer(command)

源码片段:

if (isRunning(c) && workQueue.offer(command)) {// 入队成功后可能需要唤醒线程
}

注释速记:

  • 队列没满则入队。
  • 入队后如果线程都在忙,线程池不会立刻扩容。

口诀:
队列能放,直接排队。


4. 非核心线程扩容

逻辑:

  • 当核心线程和队列都满时,允许创建新线程(最大线程数以内)。

源码片段:

else if (!addWorker(command, false))reject(command);

注释速记:

  • 只有在核心线程和队列都满时才会扩容到最大线程数。

口诀:
满员排队,再扩容。


5. 拒绝策略

方法:

  • RejectedExecutionHandler.rejectedExecution(Runnable r, ThreadPoolExecutor e)

源码片段:

public static class AbortPolicy implements RejectedExecutionHandler {public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException();}
}

注释速记:

  • 线程池和队列都满时,根据策略处理(抛异常/丢弃/调用者执行等)。

口诀:
全都满员,策略管。


6. 线程回收与销毁

方法:

  • worker.run()
  • 判断空闲时间超过keepAliveTime

源码片段:

while (task != null || (task = getTask()) != null) {// 执行任务
}

注释速记:

  • 非核心线程空闲时间到达后会被回收。
  • 核心线程默认不会被回收(可通过allowCoreThreadTimeOut配置)。

口诀:
闲太久,自动走。


三、流程口诀速记

提任务,先核心,队列排,扩满员;全满员,策略管;空闲久,自动走。


四、常用方法与内部逻辑简表

阶段关键方法/类主要逻辑说明
任务提交execute/submit任务进线程池
核心线程判断addWorker(core=true)核心线程是否有空位,有则新建
入队列workQueue.offer核心线程满,队列没满则排队
非核心线程addWorker(core=false)队列满,是否可新建非核心线程
拒绝策略RejectedExecutionHandler全部满员,执行拒绝策略
线程回收allowCoreThreadTimeOut非核心线程闲置超时自动销毁

五、源码脉络图(伪代码)

execute(command) {if (核心线程未满)addWorker(command, true)  // 新核心线程else if (队列未满)workQueue.offer(command)  // 入队列else if (线程池未满)addWorker(command, false) // 新非核心线程elsereject(command)           // 拒绝策略
}

六、速记口诀总结

场景口诀
任务进池先核心,后队列
队列满了再扩容(到最大线程数)
全满员策略管(拒绝策略)
线程回收闲太久,自动走
全流程提任务,先核心,队列排,扩满员;全满员,策略管;空闲久,自动走。

七、配图(流程图)

         +-------------------------+|      提交任务           |+-------------------------+|+-------------+-------------+|                           |
+-----v-----+               +-----v-----+
| 核心线程? |----是-------->| 创建线程  |
+-----------+               +-----------+|否|
+-----v-----+
| 队列满?   |----否-------> 入队列
+-----------+|是|
+-----v-----+
| 最大线程? |----否-------> 创建线程
+-----------+|是|
+-----v-----+
| 拒绝策略  |
+-----------+

八、结语

通过以上细化,线程池的工作原理、源码关键点、方法流程、口诀速记都一目了然。
只要记住口诀和流程图,结合源码细节,面试和实战都能轻松拿捏!

相关文章:

  • 用GPU训练模型的那些事:PyTorch 多卡训练实战
  • moveit2报错!
  • MongoTemplate 基础使用帮助手册
  • C#中UI线程的切换与后台线程的使用
  • neo4j框架:ubuntu系统中neo4j安装与使用教程
  • 小白用AI 完整的deepseek使用指南
  • 面向SDV的在环测试深度解析——仿真中间件SIL KIT应用篇
  • oracle主备切换参考
  • Python机器学习笔记(二十五、算法链与管道)
  • SearxNG本地搜索引擎
  • Visual Studio 2022 中添加“高级保存选项”及解决编码问题
  • matlab 获取DEM数据中各栅格点的经纬度
  • 汽车二自由度系统模型以及电动助力转向系统模型
  • 进程1111
  • uniapp-商城-58-后台 新增商品(属性子级的添加和更新)
  • 使用Mathematica制作Lorenz吸引子的轨道追踪视频
  • 解决uni-app开发中的“TypeError: Cannot read property ‘0‘ of undefined“问题
  • MySQL基础面试通关秘籍(附高频考点解析)
  • 技术融资:概念与形式、步骤与案例、挑战与应对、发展趋势
  • 从代码学习深度学习 - 实战Kaggle比赛:狗的品种识别(ImageNet Dogs)PyTorch版
  • 新华时评:让医德医风建设为健康中国护航
  • 农行再回应客户办理业务期间离世:亲属连续三次输错密码,理解亲属悲痛,将协助做好善后
  • 河南:响鼓重锤对违规吃喝问题露头就打、反复敲打、人人喊打
  • 娃哈哈:自4月起已终止与今麦郎的委托代工关系,未来将坚持自有生产模式
  • 普京批准俄方与乌克兰谈判代表团人员名单
  • 习近平会见哥伦比亚总统佩特罗