李锋镝的博客

  • 首页
  • 时间轴
  • 说说
  • 左邻右舍
  • 博友圈
  • 关于我
    • 关于我
    • 另一个网站
    • 我的导航站
    • 网站地图
    • 赞助
  • 留言
  • 走心评论
  • 系列文章
  • 🚇开往
Destiny
自是人生长恨水长东
  1. 首页
  2. 转载
  3. 技术
  4. 正文

ThreadPoolExecutor如何实现线程复用及超时销毁

2021年6月18日 约 644 字3 分钟 331点热度 3人点赞 0条评论
本文最后更新于 2021年6月18日,距今已 1853 天,其中的信息可能已经发生变化,请注意甄别。

以下,基于JDK1.8。

1. 线程复用

我们知道Thread.start执行之后,线程就不能再次执行了,那ThreadPoolExecutor是如何做到线程复用的呢?
原理很简单,在实际执行的线程外部套一个Thread,外层Thread的run方法while循环执行实际执行线程的run方法,实现线程的复用并且执行之后不销毁。下面是伪代码:

// 任务等待队列
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue();

new Thread(() -> {
    for (;;){
        Runnable runnable = taskQueue.poll();//队列里拿
        runnable.run();//同步执行
    }
}).start();// 异步while执行

下面是ThreadPoolExecutor的重点代码:

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) { // 阻塞获取等待任务
            w.lock();
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run(); // 实际阻塞执行
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

2. 线程销毁

我们知道,在创建线程池的时候有超时参数keepAliveTime,那么线程池是如何实现精确的超时销毁呢?

这个是结合BlockingQueue的阻塞超时来实现的,下面是源码:

 /**
 * ...
 * @return task, or null if the worker must exit, in which case workerCount is decremented
 * 翻译: 返回task,如果worker必须退出,则返回null,在这种情况下workerCount递减
 */
private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        int wc = workerCountOf(c);

        // Are workers subject to culling?
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 重点在这,如果超时没有获取到任务,则返回null,销毁线程。
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

3. 为什么用BlockingQueue

  1. 获取等待任务的时候,直接用阻塞代替通知轮询,提高性能,减少代码复杂度。
  2. 复用阻塞超时获取等待任务实现线程超时销毁,设计精巧。
  3. 本身就是支持并发操作的,不用额外维护线程安全。
除非注明,否则均为李锋镝的博客原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.lifengdi.com/transport/3456

推荐阅读

  • ThreadLocal如何解决内存泄漏问题
  • Java并发编程之如何保证线程顺序执行
  • TransmittableThreadLocal介绍与使用
  • SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
  • @Resource 和 @Autowired 的区别
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可
标签: JAVA 多线程 线程
最后更新:2021年6月18日
相关文章
  • 属性名称闹的一场乌龙事件2025年6月23日
  • SpringBoot 实现接口防刷的 5 种实现方案2025年5月27日
  • Maven发布本地项目的jar包和源码到私有仓库(maven-source-plugin的简单使用)2020年5月25日
  • 6个高频设计模式深度解析(附完整案例与避坑指南)2025年10月16日
  • 为什么生产环境不建议使用Executors快捷创建线程池?2025年2月12日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
1234567891112131415161718192021222324252627282930313233343536373839404142434446474849505152535455575859606162636465666769727476777879808182858687909293949596979899
取消回复
…

文章评论

还没有评论,快来抢沙发吧~

秋天是倒放的春天,晚安是爱你的序篇。

听点儿音乐吧 朋友~
文章目录

那年今日(07月16日)

  • 1945年:美国成功试爆世界上第一颗原子弹
  • 1936年:日本首相福田康夫出生
  • 1919年:中国科学院院士杨嘉墀出生
  • 1916年:乳酸菌之父梅契尼科夫逝世
  • 1216年:罗马教皇英诺森三世逝世
  • 更多历史事件
最新 热点 随机
最新 热点 随机
增加了两套复古皮肤-牛皮纸、千禧网页 Claude Design介绍与使用 Kratos+主题新功能介绍 Taste Skill 说明与使用 jasypt-spring-boot 使用说明 Kratos+主题新功能预览及功能演示
AI时代,个人技术博客的出路在哪里?这个域名注册整整十年了,十年时间,真快啊WordPress实现用户评论等级排行榜插件WordPress网站换了个字体,差点儿把样式换崩了做了一个WordPress文章热力图插件千万级大表新增字段实战指南:告别锁表与业务中断
AI 协作新范式:以文档为中心的开发实践指南 Consul开启transparent-proxy访问外部资源的时候,请求偶发Connection reset问题分析 提示词工程进阶指南:8大核心技巧,让AI精准读懂你的需求(2025实战版) Java并发编程之如何保证线程顺序执行 从零开发 MCP 协议工具:从原理到实战的完整指南(Python 版) Elasticsearch:cat API 介绍及其使用
最近评论
李锋镝 发布于 2 天前(07月14日) 外面的主题功能差异化比较大,部分功能没有还得通过插件来实现,这样样式也不统一,而且经常有爆出风险、漏...
瓦匠 发布于 2 天前(07月14日) 很奈斯啊,都在设计属于自己的主题了,羡慕了
rxshc 发布于 3 天前(07月13日) 工具看着挺实用的。
李锋镝 发布于 7 天前(07月09日) https://github.com/Leonxlnx/taste-skill
李锋镝 发布于 1 周前(07月06日) 哈哈哈,你那个主题做的也很棒
标签聚合
多线程 K8s MySQL JVM Spring 分布式 IDEA AI Redis JAVA MCP ElasticSearch 架构 AI编程 SpringBoot 设计模式 日常 数据库 SQL WordPress
友情链接
  • Blogs·CN
  • Honesty
  • Mr.Sun的博客
  • 临窗旋墨
  • 哥斯拉
  • 彬红茶日记
  • 志文工作室
  • 懋和道人
  • 拾趣博客导航
  • 搬砖日记
  • 旧时繁华
  • 林羽凡
  • 瓦匠个人小站
  • 皮皮社
  • 知向前端
  • 韩小韩博客
  • 风渡言

COPYRIGHT © 2026 lifengdi.com. ALL RIGHTS RESERVED.

域名年龄

Theme Kratos+ By Dylan Li

津ICP备2024022503号-3

京公网安备11011502039375号