news 2026/4/18 0:29:19

手写 Java 线程池:从状态转换到拒绝策略的极致实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手写 Java 线程池:从状态转换到拒绝策略的极致实现

🚀 引言:为什么要手写线程池?

在日常开发中,我们习惯了Executors.newFixedThreadPool()或者直接new ThreadPoolExecutor()。但你是否思考过:

  • 为什么线程池能让线程“长生不老”而不被销毁?
  • 一个int变量是如何神奇地同时表示“线程数量”和“运行状态”的?
  • 当任务洪峰来临时,线程池内部的微秒级调度逻辑是怎样的?

今天,我们摒弃那些繁琐的参数定义,直接动刀,从零实现一个具备核心调度、任务队列、拒绝策略功能的工业级线程池。


一、 核心设计:线程池的“灵魂”状态机

线程池不是简单的线程集合,而是一个复杂的状态机。在 JDK 中,作者 Doug Lea 巧妙地使用了一个AtomicInteger(32位)来存储两个信息:

  1. 高 3 位:表示线程池运行状态(RUNNING, SHUTDOWN, STOP…)。
  2. 低 29 位:表示当前有效线程数。

1.1 状态转换逻辑流

创建并初始化

调用 shutdown()

调用 shutdownNow()

任务清空

队列 & 线程池全空

线程池全空

terminated() 执行完毕

RUNNING

SHUTDOWN

STOP

TIDYING

TERMINATED


二、 第一阶段:构建核心骨架与 Worker 模型

线程池的核心在于Worker(工作者)。它本质上是一个不断从BlockingQueue中获取任务并执行的循环体。

2.1 任务承载:Worker 内部类实现

privatefinalclassWorkerimplementsRunnable{Threadthread;RunnablefirstTask;Worker(RunnablefirstTask){this.firstTask=firstTask;this.thread=newThread(this);// 真正执行的线程}@Overridepublicvoidrun(){runWorker(this);}}

2.2 核心循环:让线程“复用”的秘密

finalvoidrunWorker(Workerw){Runnabletask=w.firstTask;w.firstTask=null;try{// 【核心代码】如果任务不为空,或者从队列中能取到任务,就一直循环while(task!=null||(task=getTask())!=null){try{task.run();// 执行真正的业务逻辑}finally{task=null;}}}finally{processWorkerExit(w);// 线程退出后的清理}}

三、 第二阶段:调度逻辑——execute方法的精妙推演

当我们调用execute(runnable)时,线程池会经历三个关键判断:

  1. 核心线程数(corePoolSize):没满?直接创线程执行。
  2. 阻塞队列(workQueue):满了?尝试放进队列。
  3. 最大线程数(maximumPoolSize):队列也满了?尝试开启非核心线程。
  4. 拒绝策略(Handler):全满了?触发拒绝。

3.1 调度流程图(Mermaid 渲染)

成功

失败

提交任务 execute

当前线程数 < corePoolSize?

addWorker: 创建核心线程

workQueue.offer: 尝试入队

等待 Worker 调度

当前线程数 < maximumPoolSize?

addWorker: 创建非核心线程

执行拒绝策略 RejectedExecutionHandler


四、 第三阶段:极致实现——自定义拒绝策略

当系统负载达到极限,如何体面地拒绝任务?我们需要提供一个接口:

publicinterfaceRejectedExecutionHandler{voidrejectedExecution(Runnabler,MyThreadPoolExecutorexecutor);}// 模拟 JDK 的 DiscardOldestPolicy(丢弃最老任务策略)publicclassDiscardOldestPolicyimplementsRejectedExecutionHandler{publicvoidrejectedExecution(Runnabler,MyThreadPoolExecutorexecutor){executor.getQueue().poll();// 弹出队首executor.execute(r);// 重新尝试提交}}

五、 隐形陷阱:手写线程池时的 3 个坑

5.1 变量可见性与原子性

在增加线程计数时,必须使用AtomicIntegercompareAndSet(CAS),否则在高并发下,线程数会超出你的限制,直接撑爆内存。

5.2 线程工厂(ThreadFactory)的重要性

不要在代码里硬编码new Thread()。手写时,一定要支持传入ThreadFactory,以便为线程命名。没有名字的线程池,排查 OOM 时就是噩梦。

5.3 锁的颗粒度

在维护HashSet<Worker>(保存存活线程的容器)时,必须加全局锁(如ReentrantLock),这决定了线程池的线程安全性。


六、 总结:从手写到架构思考

通过手写,你会发现ThreadPoolExecutor的伟大之处在于它对资源的极致克制。它利用CAS + 阻塞队列,在无锁化和稳定性之间取得了近乎完美的平衡。

架构师建议:生产环境严禁使用Executors的快捷方法,一定要手动配置参数,并根据业务是CPU 密集型还是IO 密集型来计算核心线程数。


七、 互动引导

如果你在面试中遇到这道题:

“如果线程池的队列满了,但核心线程都在忙,新来的任务会发生什么?”

你能精准地回答出 addWorker 的执行时机吗?

欢迎在评论区留下你的代码实现片段。点赞过百,我将开源这套手写的“极简版 ThreadPoolExecutor”完整工程代码(包含单元测试)!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 1:16:44

一文读懂亚马逊SIOC包装测试标准

亚马逊物流中&#xff0c;自有容器运输&#xff08;SIOC&#xff09;包装需通过专项测试保障商品完好。由ISTA与亚马逊联合制定的《ISTA 6-AMAZON.COM-SIOC标准》&#xff0c;是测试核心依据&#xff0c;2016年发布后始终是卖家合规的关键参考。该标准专为亚马逊配送的SIOC商品…

作者头像 李华
网站建设 2026/4/15 4:29:19

2026版最全面Java面试汇总(面试题+答案)

今年的行情&#xff0c;让招聘面试变得雪上加霜。已经有不少大厂&#xff0c;如腾讯、字节跳动的招聘名额明显减少&#xff0c;面试门槛却一再拔高&#xff0c;如果不用心准备&#xff0c;很可能就被面试官怼得哑口无言&#xff0c;甚至失去了难得的机会。 现如今&#xff0c;…

作者头像 李华
网站建设 2026/4/17 4:13:27

惊!IF持续下跌,中科院1区Top或将降为2区

&#x1f525; &#x1f525; &#x1f525; &#x1f525; 《IEEE Transactions on Neural Networks and Learning Systems》由IEEE计算智能学会于 1990 年创刊&#xff0c;在神经网络、机器学习、深度学习及相关交叉领域享有极高的学术声誉和影响力。 值得注意的是&a…

作者头像 李华
网站建设 2026/3/12 16:32:18

基于Redis的缓存穿透与雪崩解决方案

运行效果:https://lunwen.yeel.cn/view.php?id=5462 基于Redis的缓存穿透与雪崩解决方案 摘要:随着互联网技术的飞速发展,Redis作为一种高性能的内存数据结构存储系统,被广泛应用于缓存领域。本文针对Redis缓存系统可能出现的缓存穿透和雪崩问题,提出了一系列解决方案。…

作者头像 李华
网站建设 2026/4/14 21:55:14

什么是回归测试,冒烟测试,渗透测试

一、先讲个故事&#xff1a;一栋楼的“三次验收” 假设你是开发商&#xff0c;盖了一栋居民楼&#xff0c;现在要交付给业主住。整个过程里&#xff0c;有三种完全不同的“检查”&#xff0c;分别对应&#xff1a;冒烟测试、回归测试、渗透测试。1. 冒烟测试&#xff1a;交房前…

作者头像 李华
网站建设 2026/4/10 22:38:47

从零开始学虚拟化:安全加固全指南(ESXi+vCenter + 虚拟机)虚拟化环境的安全风险具有 “牵一发而动全身” 的特性 —— 宿主主机漏洞可能导致全集群虚拟机被渗透,vCenter 权限滥用可

从零开始学虚拟化&#xff1a;安全加固全指南&#xff08;ESXivCenter 虚拟机&#xff09; 虚拟化环境的安全风险具有 “牵一发而动全身” 的特性 —— 宿主主机漏洞可能导致全集群虚拟机被渗透&#xff0c;vCenter 权限滥用可能引发数据泄露&#xff0c;跨虚拟机攻击可能突破…

作者头像 李华