Java并发编程-线程池(三)

news2025/5/21 2:44:57

文章目录

  • 线程池实现原理
    • addWorker(Runnable firstTask, boolean core)
      • 1. 状态检查:校验线程池是否允许添加线程
      • 2. 工作线程数调整:CAS保证并发安全
      • 3. 初始化变量
      • 4. 创建 `Worker` 对象并获取线程
      • 5. 加锁保证线程安全
      • 6. 启动工作线程
      • 7. 异常处理
      • 核心作用

线程池实现原理

接下来,我们进入 addWork 方法, 在创建线程前会获取全局锁:

addWorker(Runnable firstTask, boolean core)

/
 * Set containing all worker threads in pool. Accessed only when
 * holding mainLock.
 */
private final HashSet<Worker> workers = new HashSet<Worker>();
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()))
        / 若状态为STOP/TIDYING/TERMINATED(rs >= SHUTDOWN),直接拒绝新增线程。
        例外情况:当状态为SHUTDOWN且满足以下条件时允许添加 非核心线程 处理残留任务:
        1. firstTask == null(线程不携带新任务)
        2. workQueue非空(队列中仍有待处理任务)*/
            return false;
        for (;;) {
            int wc = workerCountOf(c); // 工作线程数(低29位)
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                // 容量校验
                return false;
            if (compareAndIncrementWorkerCount(c))
            // CAS递增workerCount
                break retry; // 成功则退出整个retry循环
            c = ctl.get();  // 重新读取当前ctl
            if (runStateOf(c) != rs)
                continue retry; // 状态变化则重试外层循环
            // 若仅workerCount变化,继续内层循环重试CAS
        }
    }
    boolean workerStarted = false; //标记工作线程是否成功启动
    boolean workerAdded = false;//标记线程是否被成功添加到线程池
    Worker w = null;
    try {
        final ReentrantLock mainLock = this.mainLock;
        w = new Worker(firstTask);//通过线程工厂创建Worker对象(后面讲)
        final Thread t = w.thread;//获取其绑定的线程
        if (t != null) {
            mainLock.lock(); // 获取全局锁
            try {
                //重新检查线程池状态
                int c = ctl.get();
                int rs = runStateOf(c);
                if (rs < SHUTDOWN || //线程池处于RUNNING状态时,允许添加新线程
                    (rs == SHUTDOWN && firstTask == null)) {
                    //SHUTDOWN状态下仅允许添加无初始任务的线程(处理队列中的剩余任务)
                    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) {
            //若成功添加Worker,则启动其线程(真正开始消费任务)
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
        //失败回滚:若未成功启动(如线程池已关闭),调用addWorkerFailed回滚资源
            addWorkerFailed(w);
    }
    return workerStarted;
}
private void addWorkerFailed(Worker w) {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (w != null)
            workers.remove(w); //移除Worker
        decrementWorkerCount();//减少计数
        tryTerminate(); //尝试终止线程池
    } finally {
        mainLock.unlock();
    }
}

1. 状态检查:校验线程池是否允许添加线程

int c = ctl.get();
int rs = runStateOf(c); // 运行状态(高3位)
if (rs >= SHUTDOWN &&
    !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
    return false;
  • 关键条件:

    • 若状态为STOP/TIDYING/TERMINATEDrs >= SHUTDOWN),**直接拒绝新增线程**。

    • 例外情况:当状态为SHUTDOWN且满足以下条件时允许添加**非核心线程**处理残留任务:

      • firstTask == null(线程不携带新任务)

      • workQueue非空(队列中仍有待处理任务),确保线程关闭时仍能处理队列残留任务

2. 工作线程数调整:CAS保证并发安全

for (;;) {
    int wc = workerCountOf(c); // 工作线程数(低29位)
    // 容量校验
    if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
        return false;
    // CAS递增workerCount
    if (compareAndIncrementWorkerCount(c))
        break retry; // 成功则退出整个retry循环
    // CAS失败后处理
    c = ctl.get(); // 重新读取当前ctl
    if (runStateOf(c) != rs)
        continue retry; // 状态变化则重试外层循环
    // 若仅workerCount变化,继续内层循环重试CAS
}
  • 双重校验逻辑:

    • 容量控制:通过参数core决定上限为核心/最大线程数,避免资源溢出。

    • CAS操作:通过compareAndIncrementWorkerCount原子性增加线程数,防止多线程竞争导致计数错误。

    • 失败处理:若检测到状态变化(如线程池关闭),重新进行外层状态检查。若仅线程数变化,则仅重试内层循环。

    • 双重循环:外层处理状态变化,内层处理线程数变更,分离关注点,提升并发效率。

3. 初始化变量

初始化 workerStartedworkerAddedfalse,表示工作线程未启动且未成功添加到工作线程集合。Worker 对象 w 的初始值为 null

4. 创建 Worker 对象并获取线程

w = new Worker(firstTask);
final Thread t = w.thread;

通过线程工厂创建 Worker 对象,并获取其绑定的线程 t。若线程工厂创建失败(如返回 null),后续逻辑直接跳转至第7步异常处理。

5. 加锁保证线程安全

获取 mainLock(全局锁),确保对线程池状态的检查和修改、workers 集合的操作是原子的:

6. 启动工作线程

if (workerAdded) {
    t.start();  // 启动线程
    workerStarted = true;
}

如果 Worker 成功添加到集合,则启动其绑定的线程。

7. 异常处理

finally {
    if (!workerStarted)
        addWorkerFailed(w); // 回滚失败的 Worker 操作
}
  • 若线程未启动(如锁获取后线程池已关闭),调用 addWorkerFailed 移除 Worker 并更新线程池状态。

核心作用

这段代码是线程池 ThreadPoolExecutor中添加工作线程的核心逻辑,它会创建Worker,Worker内置了一个线程(由线程工厂创建),这个线程会在Worker创建后启动,专门用于执行Worker的run()方法。另外还实现了:

  1. 线程安全的 Worker管理:通过 ReentrantLock 保证对共享变量(如 workers 集合)的原子操作。

  2. 状态双重检查:防止在加锁期间线程池状态发生变化。

  1. 异常回滚机制:确保部分失败的操作能被正确处理,保证线程池的稳定性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2380398.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《黑马前端ajax+node.js+webpack+git教程》(笔记)——node.js教程+webpack教程(nodejs教程)

黑马程序员前端AJAX入门到实战全套教程&#xff0c;包含学前端框架必会的&#xff08;ajaxnode.jswebpackgit&#xff09;&#xff0c;一套全覆盖 文章目录 Node.js与Webpack-01.Node.js入门定义和作用什么是前端工程化&#xff1f;&#xff08;离不开node.js&#xff09;Node.…

Flink 快速入门

本文涉及到大量的底层原理知识&#xff0c;包括运行机制图解都非常详细&#xff0c;还有一些实战案例&#xff0c;所以导致本篇文章会比较长&#xff0c;内容比较多&#xff0c;由于内容太多&#xff0c;很多目录可能展示不出来&#xff0c;需要去细心的查看&#xff0c;非常适…

阻塞队列:线程安全与生产者消费者模型解析

一、阻塞队列 阻塞队列就是基于普通队列做出扩展 1.线程安全的 如果针对一个已经满了的队列进行入队列&#xff0c;此时入队列操作就会阻塞&#xff0c;一直阻塞到队列不满&#xff08;其他线程出队列元素&#xff09;之后 如果针对一个已经空了的队列进行出队列&#xff0c…

【入门|Docker】基础知识扫盲:什么是 Docker?

文章目录 基础知识扫盲&#xff1a;什么是 Docker&#xff1f;Docker 是什么&#xff1f;Docker 核心组件Docker 与虚拟机的区别Docker 在现代开发中的核心角色Docker 的局限性 基础知识扫盲&#xff1a;什么是 Docker&#xff1f; 最近打算开始系统性地学习与云计算相关的技术…

【MYSQL】基本查询,表的增删查改

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 |&#x1f5c3;️ mysql 摘要&#xff1a;本文详细介绍了MySQL中的CRUD操作&#xff08;创…

Android Studio 日志系统详解

文章目录 一、Android 日志系统基础1. Log 类2. 日志级别 二、Android Studio 中的 Logcat1. 打开 Logcat2. Logcat 界面组成3. 常用 Logcat 命令 三、高级日志技巧1. 自定义日志工具类2. 打印方法调用栈3. 打印长日志4. JSON 和 XML 格式化输出 四、Logcat 高级功能1. 自定义日…

Feign异步模式丢失上下文问题

Feign异步模式丢失上下文问题 问题描述 当我们使用异步对我们代码进行操作优化时&#xff0c;代码中使用了RequestContextHolder去获取上下文的数据&#xff0c;当我们执行原来可以执行的业务时发现报了空指针异常或数据为空&#xff0c;这是为什么呢&#xff1f; 原理解释 …

【AWS入门】Amazon SageMaker简介

【AWS入门】Amazon SageMaker简介 [AWS Essentials] Brief Introduction to Amazon SageMaker By JacksonML 机器学习(Machine Learning&#xff0c;简称ML) 是当代流行的计算机科学分支技术。通常&#xff0c;人们在本地部署搭建环境&#xff0c;以满足机器学习的要求。 AWS…

MYSQL 故障排查与生产环境优化

目录 一.前置知识点 1. 案例需求 &#xff08;1&#xff09;mysql 常见故障解决 &#xff08;2&#xff09;mysql 性能优化 2.案例实施思路 &#xff08;1&#xff09;单库常见故障分析 &#xff08;2&#xff09;主从常见故障分析 &#xff08;3&#xff09;从几个不同…

解决使用@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss“, timezone = “GMT+8“)时区转换无效的问题

前言 对于一些时间的字段&#xff0c;我们从数据库查询出来通常需要转换后返回给前端展示&#xff0c;前端需要的格式一般为yyyy-MM-dd HH:mm:ss&#xff0c;可以通过JsonFormat注解来作转换和时区转换。 问题场景 原因 LocalDateTime类本身不带时区信息所以转换无效 解决办…

计算机网络概要

⽹络相关基础知识 协议 两设备之间使⽤光电信号传输信息数据 要想传递不同信息 那么⼆者ᳵ就需要约定好的数据格式 层 封装 继承 多态是计算机的性质 它们⽀持了软硬件分层的实现 同层协议可以ᳵ接通信 同层协议ᳵ不直接通信 是各⾃调⽤下层提供的结构能⼒完成通信 分层…

Word压缩解决方案

Word压缩解决方案&#xff1a;基于图片压缩的 .docx 优化实践 &#x1f4cc; 背景 在日常科研写作或项目文档整理中&#xff0c;Word 文档&#xff08;.docx&#xff09;往往因为插入大量高清图表、扫描图像、公式图等导致文件体积过大&#xff0c;或者毕业学位论文查重要求上…

TDengine 2025年产品路线图

TDengine OSS 之 2025 年年度路线图如下表所示。 季度功能2025Q1 虚拟表查询能力&#xff1a;REGEXP、GREATEST、LEAST、CAST 函数支持判断表达式、单行选择函数的其他列值、INTERP 支持插值时间范围存储能力&#xff1a;支持将查询结果写入超级表、超级表支持 KEEP 参数、STM…

Ubuntu服务器部署多语言项目(Node.js/Python)方式实践

Ubuntu服务器部署多语言项目&#xff08;Node.js/Python&#xff09;方式实践 服务器脚本运行方式命令行直接执行nohup后台执行进程 Screen概述安装基本操作命令启动 Screen退出当前会话&#xff08;不终止进程&#xff09;查看所有会话重连会话关闭会话 常用快捷键典型使用场景…

计算机网络 - 2.基础协议

1.TCP协议 1.TCP(Transmission Control Protocol):传输控制协议2.TCP协议是一种面向连接的、可靠的、 基于字节流的传输层通信协议 1.面向连接:两个使用TCP协议的应用(通常一个客户和一个服务器)在彼此交换数据包之前必须先建立一个TCP连接2.可靠的 1.数据传输之前都要建立…

初识css,css语法怎样学好css以及常见问题与避坑

一、CSS 是什么&#xff1f; CSS&#xff08;Cascading Style Sheets&#xff09;是一种用于描述网页文档&#xff08;HTML 或 XML&#xff09;呈现样式的语言。它负责控制网页元素的视觉表现&#xff0c;如颜色、字体、布局等&#xff0c;使内容与展示分离。 二、CSS 语法结构…

Axure疑难杂症:垂直菜单展开与收回(4大核心问题与专家级解决方案)

亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!如有帮助请订阅专栏! Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:垂直菜单展开与收回 主要内容:超长菜单实现、展开与收回bug解释、Axure9版本限制等问题解…

vue2.0 组件生命周期

个人简介 &#x1f468;‍&#x1f4bb;‍个人主页&#xff1a; 魔术师 &#x1f4d6;学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全栈发展 &#x1f6b4;个人状态&#xff1a; 研发工程师&#xff0c;现效力于政务服务网事业 &#x1f1e8;&#x1f1f3;人生格言&…

在Linux服务器上部署Jupyter Notebook并实现ssh无密码远程访问

Jupyter notebook版本7.4.2&#xff08;这个版本AI提示我Jupyter7&#xff08;底层是 jupyter_server 2.x&#xff09; 服务器开启服务 安装Jupyter notebook 7.4.2成功后&#xff0c;终端输入 jupyter notebook --generate-config 这将在 ~/.jupyter/ 目录下生成 jupyter_…

GPU 超级节点:AWS Trainium2 UltraServer

目录 文章目录 目录时间线Inferentia1Trainium1Inferentia2Trainium2Trainium2 ServerTrainium2 UltraServerTrainium2 UltraClustersTrainium3AWS GPU 实例矩阵与竞品分析SuperNode RackTrn2 ServerTrn2U Server ScaleUp 网络PCIe Gen5&#xff1a;CPU-Trainium2 ScaleUpNeuro…