ThreadPoolExecutor类源码分析

别再怕DRIVER_VERIFIER_DMA_VIOLATION蓝屏:手把手教你用WinDbg分析IOMMU与驱动冲突 本文深入解析DRIVER_VERIFIER_DMA_VIOLATION蓝屏错误,从IOMMU原理到实战排错,手把手教你使用WinDbg分析驱动冲突。通过理解DMA与IOMMU的核心机制、搭建分析环境、解读DMAR表与设备拓扑,最终定位问题驱动并提供解决方案,帮助开发者和IT运维人员有效应对此类系统崩溃问题。 阅读详情

前言

  Java中的线程池通过复用线程来提高多线程任务的执行效率,而ThreadPoolExecutor就是Java中线程池的核心类之一,它将线程的创建、管理以及资源调度进行了封装,使用ThreadPoolExecutor能够方便地管理多个线程的生命周期和执行。

ThreadPoolExecutor的数据结构

  ThreadPoolExecutor包含几个重要的数据结构:workers用来存储线程池中的线程,workQueue用来存储等待执行的任务,mainLock用于保护线程池状态的改变。下面是ThreadPoolExecutor类的定义:

public class ThreadPoolExecutor extends AbstractExecutorService {
    // 线程池中实际运行的线程数
    private volatile int poolSize;
    // 线程池中允许同时存在的最大线程数
    private final int maximumPoolSize;
    // 线程池任务缓冲队列
    private final BlockingQueue<Runnable> workQueue;
    // 线程工厂,用于创建新的线程
    private final ThreadFactory threadFactory;
    // 拒绝策略,用于处理无法处理的任务
    private final RejectedExecutionHandler handler;
    // ThreadPoolExecutor状态锁
    private final Object mainLock = new Object();
    // 线程池是否关闭
    private volatile boolean shutdown;
    // 线程池中所有 worker 数组
    private final HashSet<Worker> workers = new HashSet<>();
    // 线程池最大任务等待时间,超过此时间未得到线程而造成的任务拒绝处理
    private volatile long keepAliveTime;
    ... // 其他属性和方法
}

线程池的创建和启动的源码分析

  ThreadPoolExecutor提供了几个构造函数用于创建线程池对象,在构造函数中会初始化线程池中所需的各项参数,在ThreadPoolExecutor的execute方法中将任务交给线程池进行管理和调度。下面是关键代码:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
                          TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new SynchronousQueue<Runnable>(), Executors.defaultThreadFactory(), defaultHandler);
    this.workQueue = workQueue;
}

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
        if (runState == RUNNING && workQueue.offer(command)) { // 将任务添加到任务队列
            if (runState != RUNNING || poolSize == 0)
                ensureQueuedTaskHandled(command);
        }
        else if (!addIfUnderMaximumPoolSize(command)) // 创建新线程处理任务
            reject(command); 
    }
}

线程池的任务提交的源码分析

  ThreadPoolExecutor的任务提交机制采用BlockingQueue来实现,任务首先会进入BlockingQueue,如果线程池中已经存在空闲的线程,则会直接将任务交给空闲线程处理;如果线程池中没有空闲的线程,则会创建新的线程来处理任务。下面是ThreadPoolExecutor中任务提交的关键代码:

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);
}

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        if (rs >= SHUTDOWN &&
            !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
            return false;
        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;
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int rs = runStateOf(ctl.get());
                if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) 
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

  execute方法接受一个Runnable类型的参数,用于代表任务。如果传入的参数是null,就会抛出NullPointerException异常。在execute方法内部,首先获取线程池的状态和当前线程池中worker的数量。如果worker的数量小于核心线程池大小(corePoolSize),那么调用addWorker方法启动新的线程去执行该任务,接着返回。如果worker的数量已经达到或超过核心线程池大小,并且线程池此时处于运行状态(RUNNING),那么将这个任务添加到阻塞队列中以便后续处理。否则,如果阻塞队列已满,那么会尝试使用addWorker方法创建worker,如果创建失败就会调用reject方法进行拒绝处理。

  addWorker方法的作用是添加一个新的Worker线程到线程池中,用于执行任务。该方法首先获取整个线程池的状态和worker数量,如果线程池处于SHUTDOWN或STOP状态,或者阻塞队列非空且firstTask为null,则不再添加worker,并返回false。其次,如果当前worker数量已经等于线程池最大容量或者已达到核心线程池大小(如果core参数为true),也不再添加worker。最后,如果成功增加worker计数,那么创建一个新的Worker对象(传入的是firstTask),加入到workers列表中,然后使用线程池的锁(mainLock)加锁,将largestPoolSize设置为最新的线程池大小,并启动新的线程进行任务执行。

线程池的异常处理的源码分析

  ThreadPoolExecutor线程池的异常处理机制包括两个方面:一是线程池内部可能会产生异常,需要进行自我保护和恢复;二是线程池的任务执行过程中可能会因为执行任务代码发生异常而导致线程池出现问题。

  线程池内部的异常处理包括在addWorker方法中对worker数量限制的检查,如果超出了capacity或者corePoolSize/maximumPoolSize,就会返回false。此外,在Worker.run方法内部,还有try-catch语句来捕获任务代码内部的异常并处理。当任务执行出现异常时,该线程会停止运行,从workers列表中移除并尝试创建新的线程来替换它。

  线程池中的任务执行异常处理则需要通过RejectedExecutionHandler接口来实现。线程池默认的拒绝策略是AbortPolicy,即直接抛出RejectedExecutionException异常。该异常会被runWorker方法捕获并调用processWorkerExit方法进行处理,其中主要是将异常打印输出到控制台。除此之外,用户也可以自定义RejectedExecutionHandler来处理任务执行异常,从而实现自定义的异常处理策略。

  综上,ThreadPoolExecutor线程池的异常处理机制主要包括内部自我保护和恢复机制以及用户自定义的任务执行异常处理机制。通过在代码中使用try-catch语句来捕获任务执行内部的异常,并且定义RejectedExecutionHandler接口来实现自定义的异常处理策略。

学习ThreadPoolExcutor的好处

  1. 学习ThreadPoolExecutor的源码可以带来以下好处:

  2. 更深入地理解线程池的工作原理和内部机制,从而更好地使用和优化线程池。

  3. 掌握线程池的异常处理机制,预防和解决线程池在任务执行过程中产生的异常情况。

  4. 了解线程池的实现细节,例如如何添加或删除线程、如何保证任务的有序处理等,从而提高编程技巧和代码质量。

  5. 理解并扩展JDK提供的线程池实现,在特定的业务场景下可以对线程池进行个性化定制,满足自身应用的需求。

  6. 深入掌握线程池的源码还可以为后续研究和实践相关技术打下坚实的基础,例如并发编程,分布式系统等。

IDEA的使用指南 IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧. 立即下载

相关推荐

DESeq2实战:利用LRT检验解析时间序列基因表达动态变化

本文详细介绍了如何使用DESeq2中的LRT检验分析时间序列基因表达数据,揭示基因表达动态变化模式。通过构建完整模型与简化模型比较,LRT检验能有效识别处理效应随时间变化的基因,适用于发育过程、疾病进展等研究。文章提供了从数据准备、模型构建到结果可视化的完整实战指南,并分享了高级技巧与常见问题排查方法。

weixin_29062671的博客 439

【线程池】史上最全的ThreadPoolExecutor源码详解

史上最全的ThreadPoolExecutor源码详解,一篇文章带你彻底搞懂ThreadPoolExecutor底层原理。

小七的博客 3969

ICG setup timing violation介绍?

门控时钟(clock gating)在RTL级电路设计过程中进行低功耗优化常用方法,能够有效降低动态功耗(翻转功耗)。Clock gating cell 可以由与门,与非门,或门或者或非门构成,但很容易产生Glitch。在实际使用中,一般用ICG(集成门控时钟单元)来完成clock gating。 下图展示了glitch的产生原因 在CTS时钟树综合的时候,ICG不会被看作sink,通常放置在source点附近,因此就会出现如上图这种结果。上图可以看出,在分析DFF到ICG的setup timing

m0_61003348的博客 9802

线程池(ThreadPoolExecutor)源码解析

目录一、线程池概念介绍1.1、什么是线程池1.2、线程池工作流程1.3、线程池的代码用例二、源码解析——构造函数2.1、线程池的构造函数及类的继承关系2.2、Executors提供的线程池模板2.3、拒绝策略的实现2.4、任务队列BlockingQueue的实现三、 源码解析——execute(Runnable command)3.1、流程概述 一、线程池概念介绍 1.1、什么是线程池 池化技术其实在技术生态圈中是比较常见的,比如:对象池、连接池等等。 为什么会有线程池这个东西存在呢?其实原因跟其他池化技

小志的博客 8746

Jmeter压测报告

账户分析压测报告 一、测试内容 本次测试是针对账户分析进行的压力测试,在账户分析查询接口中,只对用户资产查询接口进行压力测试,其中不包含用户签名校验功能。 二、测试方法 本次采用apache的开源测试工具jmeter,采用本地动态拼装请求数据并通过http协议GET方式发送每日盈亏查询请求。并采用1000个用户账号测试访问情况。...

qq_31108731的博客 6624

79、昇腾系列服务器/昇腾系列推理卡/昇腾系列嵌入式开发板+Dify+one api部署DeepSeek-R1-Distill-Qwen-32BW8A8+RAG本地模型知识库和负载均衡双实例

阶段,安装过程缺什么,,在docker外面git下源码,进入容器内部进行量化,这里的容器建议在创建个8卡的容器,双卡容器量化会显示npu显存不够,除非你用cpu转模型,我就懒得创建容器了,使用cpu量化吧,巨慢;创建容器,进入容器,计划使用两张昇腾NPU卡推理DeepSeek-R1-Distill-Qwen-32B的W8A8模型,所以构建的容器用两张卡,选6、7卡吧,0-6号卡可以跑文本嵌入模型、重排序模型;直接进入量化阶段,在容器外面操作即可,环境不用管,因为系统已经默认配置了环境,直接跳到。

sxj731533730 6116

【线程池】史上最全的ScheduledThreadPoolExecutor源码分析

史上最全的ScheduledThreadPoolExecutor源码分析,一篇文章带你分析ScheduledThreadPoolExecutor底层原理,带你彻底学会定时任务线程池。

小七的博客 1438

全球APN信息汇总

全球APN信息,电信APN,移动APN,联通APN,台湾APN,马来西亚APN,俄罗斯APN,日本APN,泰国APN,美国APN,英国APN,法国APN,德国APN,意大利APN,葡萄牙APN,土耳其APN,荷兰APN,丹麦APN,比利时APN,爱尔兰APN,新加坡APN,越南APN,老挝APN,菲律宾APN,印尼APN,泰国APN,柬埔寨APN,巴基斯坦APN,印度APN,奥地利APN,保加利亚APN,捷克APN,立陶宛APN,罗马尼亚APN,挪威APN,希腊APN,匈牙利APN,瑞士APN,乌克兰APN

renkai721的专栏 2796

ThreadPoolExecut线程池底层源码分析

ThreadPoolExecut线程池底层源码分析

weixin_48043343的博客 397

Video Diffusion Models:基于扩散模型的视频生成

Diffusion Models专栏文章汇总:入门与实战 前言:扩散模型已经被广泛运用到图像生成、image-to-image转换、时间序列生成、3D点云生成、文本生成、音频生成等领域,谷歌研究院最新的研究成果成功将diffusion models运用到视频生成领域。 目录 模型结构 分解时空体系联合训练 梯度条件法 恐怖的实验结果 论文和代码 个人启发 个人疑问? 模型结构 在前面的博文中,我详细介绍了为什么绝大部分的diffusion models都使用Unet结构.

沉迷单车的追风少年 6669

2025年CSP-J复赛真题及题解:T4 多边形(polygon)

2025年CSP-J复赛真题及题解:T4 多边形(polygon)

王老师青少年编程 1716

ThreadPoolExecutor源码解析

ThreadPoolExecutor源码解析。

qq_35920289的博客 260

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Java线程池ThreadPoolExecutor类源码分析

前面我们在java线程池ThreadPoolExecutor类使用详解中对ThreadPoolExector线程池类的使用进行了详细阐述,这篇文章我们对其具体的源码进行一下分析和总结; 首先我们看下ThreadPoolExecutor用来表示线程池状态的核心变量 //用来标记线程池状态(高3位),线程个数(低29位) //默认是RUNNING状态,线程个数为0 priva...

dianyuzhi7625的博客 203

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

线程池ThreadPoolExecutor类源码分析

Java并发编程:线程池的使用   在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:   如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。   那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任

思考、总结、专注 1026

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java并发编程:ThreadPoolExecutor类及方法源码分析

ThreadPoolExecutor是jdk自带线程池实现类,现有的Executors工具类实现的几种线程池核心都是调用ThreadPoolExecutor类。ThreadPoolExecutor在jdk1.7及以后做了部分修改,本文以JDK1.8为准。1 构造函数ThreadPoolExecutor类共有4个构造函数,其他三个构造函数都是调用下参数最全的一个,下面只介绍参数最全的的一个。 publ

ahsxsk的学习之路 742

ThreadPoolExecutor源码分析

从类接口,成员变量,重点方法介绍线程池ThreadPoolExecutor和 ScheduledThreadPoolExecutor

u014516441的博客 225

线程池ThreadPoolExecutor分析(源码版)

线程池ThreadPoolExecutor分析(源码版)

qq_39296070的博客 915

手撕ThreadPoolExecutor线程池源码

这篇文章对ThreadPoolExecutor创建的线程池如何操作线程的生命周期通过源码的方式进行详细解析。通过对execute方法、addWorker方法、Worker类、runWorker方法、getTask方法、processWorkerExit从源码角度详细阐述,文末有彩蛋。 ex...

chouji7537的博客 102

JAVA 线程池 ThreadPoolExecutor

目录 一、ThreadPoolExecutor简介 二、运行原理 三、源码分析 四、扩展 一、ThreadPoolExecutor简介 ThreadPoolExecutor是我们在Java中常用的线程池类,当然我们经常用如下方法创建,但是这些方法内部最终还是通过ThreadPoolExecutor构造的。(所以我有时候很不理解,为什么一说直接用ThreadPoolExecutor...

han_dada的博客 502

ThreadPoolExecutor 源码分析

文章目录前言源码分析crlWorker构造方法的参数execute(提交任务)addWorker小结下execute的步骤执行任务runWorkergetTask小结下执行任务的步骤参考 前言 ThreadPoolExecutor是线程池的默认实现,在使用线程池的时候,如果没有特殊要求,则直接创建ThreadPoolExecutor。如果有特殊要求,则直接继承ThreadPoolExecutor,...

FengZH的博客 219

ThreadPoolExecutor结合源码分析运行原理

ThreadPoolExecutor源码分析核心接口ExecutorExecutorServiceAbstractExecutorService源码分析内部工作原理构造方法赋值属性分析内部工作类Worker线程池运行思路Worker类源码分析构造方法addWorker方法分析run方法runWorker方法getTask方法processWorkerExit方法tryTerminate方法shutdown方法shutdownNow方法interruptIdleWorkers方法interruptIfStar

j222085的博客 174

Java并发之线程池ThreadPoolExecutor源码分析学习,java面试题,java高级笔试题

写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫码加微信好友进【程序员面试学习交流群】,免费领取。也欢迎各位一起在群里探讨技术。 线程池学习 以下所有内容以及源码分析都是基于JDK1.8的,请知悉。 我写博客就真的比较没有顺序了,这可能跟我的学习方式有关,我自己也觉得这样挺不好的,但是没办法说服自己去改...

ccc_ccc8的博客 302

线程池之ThreadPoolExecutor线程池源码分析笔记

1.线程池的作用 一方面当执行大量异步任务时候线程池能够提供较好的性能,在不使用线程池的时候,每当需要执行异步任务时候是直接 new 一线程进行运行,而线程的创建和销毁是需要开销的。使用线程池时候,线程池里面的线程是可复用的,不会每次执行异步任务时候都重新创建和销毁线程。 另一方面线程池提供了一种资源限制和管理的手段,比如可以限制线程的个数,动态新增线程等,每个ThreadPoolExecu...

weixin_30760895的博客 192

解析ThreadPoolExecutor类是如何保证线程池正确运行的

摘要:对于线程池的核心类ThreadPoolExecutor来说,有哪些重要的属性和内部类为线程池的正确运行提供重要的保障呢?

华为云官方博客 1150

JDK ThreadPoolExecutor核心原理与实践

一、内容概括 本文内容主要围绕JDK中的ThreadPoolExecutor展开,首先描述了ThreadPoolExecutor的构造流程以及内部状态管理的机理,随后用大量篇幅深入源码探究了ThreadPoolExecutor线程分配、任务处理、拒绝策略、启动停止等过程,其中对Worker内置类进行重点分析,内容不仅包含其工作原理,更对其设计思路进行了一定分析。文章内容既包含了源码流程分析,还具有设计思路探讨和二次开发实践。 二、构造ThreadPoolExecutor 2.1线程池参数列表 .

wdjnb的博客 431

线程池源码分析

上面我们说完了任务提交的大概流程,但你有没有想过添加到阻塞队列中的任务好像并没有被执行,一个Worker执行完了任务又会怎么样?还有就是线程池的异常处理,按理来说如果一个异常没有被捕获,线程就会挂掉,挂掉后线程池的线程数量就会减小,那么线程池是怎么保证线程的数量的呢。带着问题,我们继续。这个应该还是很好理解的吧,经过计算ctlOf(RUNNING, 0),初始化的ctl其实就是11100000000000000000000000000000,这个值表示的是线程池为RUNNING状态,0条工作线程。

qq_51470789的博客 190
上一篇: 深入解析Java ConcurrentHashMap类的源码
下一篇: 程序员眼中的二进制
JavaWizard-M
博客等级 码龄6年 3159粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值