【并发专题】线程池ThreadPoolExecutorl底层原理源码分析

news2024/12/22 23:27:38

目录

  • 前置知识
  • 课程内容
    • 一、线程池
      • 1.基本介绍
      • 2.Executor接口
      • 3.线程池的重点属性
        • ctl字段
        • RUNNING字段
        • SHUTDOWN字段
    • 二、线程池的创建及参数解读
    • 三、核心源码解读
  • 学习总结

前置知识

Q1:终止一个线程的方法有哪些?
答:通常有4个方法。其中前2个是使用stop()和destroy()方法终止,但是这2个都不推荐使用,因为他们是暴力终止线程,所以不保证资源被正确释放,甚至导致数据不一致。后2个则是通过设置一个线程中断标记了,自定义的中断标记(保证内存可见性),或者使用线程自有的interupte()方法。

Q2:为什么需要线程池?
答:首先线程池严格来说是一种池化技术,重在资源的重复利用。另外我们也知道,JAVA的线程实现技术是【内核线程1:1】的实现方案,这势必造成,JAVA在创建线程的时候,涉及到【用户态】【内核态】的切换,所以算是比较重型的操作。
试想一下,在web开发中,服务器需要接受并处理请求,如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁线程,如此一来会大大降低系统的效率。可能出现服务器在为每个请求创建新线程和销毁线程上花费的时间和消耗的系统资源要比处理实际的用户请求的时间和资源更多。所以,我们需要一个可重复使用的线程池。线程池的优势在于:

  • 重用存在的线程,减少线程创建,消亡的开销,提高性能
  • 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行
  • 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控

课程内容

一、线程池

1.基本介绍

线程池严格来说是一种池化技术,重在资源重复利用,它就是一种多线程存在形式。在多线编程中,创建和销毁线程一项开销较的操作,所以线程池通过预先创建一组线程,并将任务分配给这些线程来提供高效的线程管理。
线程池通常包括一个线程队列和一个任务队列。线程队列中保存着可供复用的线程,任务队列中保存着需要执行的任务。
从上面我们可以看到,线程池有着显著的优点:降低资源消耗、提高响应速度、方便管理;可以复用线程、控制最搭并发数、管理线程等。

2.Executor接口

Executor接口是线程池框架中最基础的部分,定义了一个用于执行Runnable的execute方法。它的继承图如下:
在这里插入图片描述

从图中我们可以看到一个很重要的接口叫做Executors,这也是我们后面学的线程池的一个核心接口。在其中定义了线程池的具体行为。接口定义如下:
在这里插入图片描述

execute(Runnable command); // 执行Ruannable类型的任务
submit(task); // 可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
shutdown(); // 表示要关闭线程池,不再接受新的任务,但是会把已经提交的任务先完成
shutdownNow(); // 停止所有正在执行的任务,不再接受新的任务,并且也不执行等待种的任务,只是将等待任务列表返回
isTerminated(); // 测试是否所有任务都执行完了(只有调用了shutdown或者shutdownNow这里才可能返回真,不然永远是false)
isShutdown(); // 测试是否该ExecutorService已被关闭

3.线程池的重点属性

线程池中的重点属性如下:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// 线程池的状态
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

ctl字段

  • AtomicInteger ctl:ctl字段,是对线程池的运行状态和线程池中有效线程的数量进行控制的一个字段,它包含两部分信息:【线程池的运行状态,runState】和【线程池有效线程数量,workerCount】。这里可以看到,使用了Integer类型来保存。其中,高3位保存runState低29位保存了workerCount。上面的COUNT_BITS 值就是29,所以CAPACITY的值是1左移29,很大很大,大概5亿多。

下面5个字段表示线程池的状态:

RUNNING字段

(1)状态说明:表示线程池出于RUNNING状态。在当前状态,可以接收新任务,以及对线程已添加的任务进行处理。
(2)状态切换:线程池的初始状态就是RUNNING状态。换句话说,线程池一旦被创建就出于这个状态了,并且线程池的任务数量为0

SHUTDOWN字段

(1)状态说明:表示线程池处于SHUTDOWN状态。在当前状态,不接收新任务,但能处理已经添加的任务

  • STOP:
  • TIDYING:
  • TERMINATED:

二、线程池的创建及参数解读

ThreadPoolExecutor提供了两种执行任务的方法:

void execute(Runnable command); // 执行一个任务,没有返回值
Future<?> submit(Runnable task); // 执行一个任务,有返回值

本质上submit中最终还是调用的execute()方法,只不过会将任务包装成一个RunnableFuture返回一个Future对象,用来获取任务执行结果:

public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

下面是线程池的基本使用示例:

public class ThreadPoolExecutorTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                2,
                10,
                60,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>()
        );

        // 演示无返回值
        Runnable noReturn = new Runnable() {
            @Override
            public void run() {
                System.out.println("这里经过周密的计算返回:1");
            }
        };
        threadPoolExecutor.execute(noReturn);

        // 演示有返回值
        Callable haveReturn = ()->{
            return "这里经过周密的计算返回:2";
        };
        Future submit = threadPoolExecutor.submit(haveReturn);
        System.out.println(submit.get());
    }

//    系统输出:
//    这里经过周密的计算返回:1
//    这里经过周密的计算返回:2
}

在上面的例子中,我们手动新建了一个线程池,没有采用Executors提供的静态工厂方法。ThreadPoolExecutor的构造方法有4个,但是总的来说算是1个,其他3个都是某些参数采用了默认策略而已。所以这边就拿最全面的那个来给大家介绍一下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

那么,一个任务进入线程线程池添加任务流程及线程增加策略如下:
在这里插入图片描述

三、核心源码解读

学习总结

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

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

相关文章

机械制造三维虚拟仿真实训的优点

机械制造三维虚拟仿真实训系统是一种基于计算机技术的机械原理仿真软件&#xff0c;它可以模拟各种机械系统的运动和受力情况&#xff0c;帮助用户深入了解机械原理的工作原理和应用。该系统采用三维建模技术&#xff0c;将机械系统的各个部分进行数字化建模&#xff0c;并通过…

科研院所用泛微搭建信创办公平台,统一办公,业务融合,安全便捷

国家全面推动重要领域的信创改造工作&#xff0c;要求到2027年底&#xff0c;对综合办公、经营管理、生产运营等系统实现“应替尽替、能替则替”。 科研机构作为智力、知识密集型机构&#xff0c;承载着大量数据、信息资产&#xff0c;数字化程度高&#xff0c;业务系统多样&a…

阿里云部署 ChatGLM2-6B 与 langchain+ChatGLM

1.ChatGLM2-6B 部署 更新系统 apt-get update 安装git apt-get install git-lfs git init git lfs install 克隆 ChatGLM2-6B 源码 git clone https://github.com/THUDM/ChatGLM2-6B.git 克隆 chatglm2-6b 模型 #进入目录 cd ChatGLM2-6B #创建目录 mkdir model #进入目录 cd m…

MySql增删改查基础

目录 1.基本操作 1.1新增 1.2查询 1.2.1指定查询 1.2.2排序查询 1.2.3分页查询 1.3修改 1.4删除 2.进阶操作 2.1键值约束 2.1.1主键约束 2.1.2唯一键约束 2.1.3非空约束 2.1.4默认值 2.1.5自增属性 ​编辑 2.1.6外键约束 2.1.7check子句 3.表的设计 3.1ER关…

海上港口三维数据可视化展示提升应急救援效率

3D可视化技术可以将复杂数据转化为生动的图形和模型&#xff0c;使得数据的关联和趋势更加明确和易于理解。通过使用3D模型和图形&#xff0c;我们可以更直观地观察数据之间的关系&#xff0c;发现隐藏在数据背后的规律和模式。例如&#xff0c;在工业领域&#xff0c;利用3D可…

jdk,jre和jvm三者的关系和区别

目录 一、三者的关系 二、JDK的概念 三、JRE的概念 四、JVM的概念 五、三者区别 一、三者的关系 从图中可以清楚地看到&#xff0c;他们之间的关系是JDK包含JRE, JRE又包含JVM。 因此&#xff0c;JDK包含JRE和JVM。 JDK JRE Java 开发工具包 [Java,Javac,Javadoc,Javap…

Python实现九宫格数独小游戏

1 问题 有1-9个数字&#xff0c;将他们填入一个3*3的九宫格中&#xff0c;使得他们的每行&#xff0c;每列&#xff0c;以及对角线上的和相等&#xff0c;且要求每个格子的数字不可以重复。使用python列出所有可能的组合。示例如下: 2 方法 每行&#xff0c;列&#xff0c;对角…

#pragma region用法

简介 #pragma region 是VS(Visio Studio)所特有的预处理语法&#xff08;其他IDE或者Cmake会报错&#xff09;&#xff0c;其可以用来收缩或者展开一段代码。 #pragma region MyRegion// ...Code content #pragma endregion 其中&#xff0c;MyRegion 即给这代码块所定义的名…

【python中级】将字符串按照固定长度分割

【python中级】将字符串按照固定长度分割 1、背景2、代码1、背景 近期有将图片进行base64编码成字符串的工作,参考博客: 【python中级】 base64编码将图片数据转化为成字符串 https://jn10010537.blog.csdn.net/article/details/131894686 我将图片编码成字符串后,再写到p…

地震反演基础知识1

文章目录 地震反演基础知识11. 基础知识1.1 正演反演1.2 地震数据1.3 速度模型1.4 道1.5 FWI的端到端深度学习1.6 传统FWI vs. DL-FWI 2. 数据信息2.1 数据集的层级关系2.2 SEG盐体数据2.3 OpenFWI数据集 地震反演基础知识1 1. 基础知识 1.1 正演反演 正演 根据地下介质的参…

electron的electron-packager打包运行和electron-builder生产安装包过程,学透 Electron 自定义 Dock 图标

electron的electron-packager打包运行和electron-builder生产安装包过程 开发electron客户端程序&#xff0c;打包是绕不开的问题。 macOS 应用构建&#xff0c;看似近在咫尺&#xff0c;实则坑坑致命。 场景&#xff1a;mac笔记本打包&#xff0c;以及生产出可交付的软件安装…

自学网络安全(黑客)的误区

前言 网络安全入门到底是先学编程还是先学计算机基础&#xff1f;这是一个争议比较大的问题&#xff0c;有的人会建议先学编程&#xff0c;而有的人会建议先学计算机基础&#xff0c;其实这都是要学的。而且这些对学习网络安全来说非常重要。 一、网络安全学习的误区 1.不要…

windows系统安装ArtemisMQ

windows系统安装ArtemisMQ ArtemisMQ介绍 apache-artemi 是apache-activemq的新一代MQ产品。 特点&#xff1a; 1.支持多种mq协议&#xff0c;如jms\amqp\mqtt等协议。 2.部署方便&#xff0c;可以快速生成多个broker实例&#xff0c;以及部署集群。 3.已提供spring-boot-sta…

学习数学助手Schooltech Math Resource Studio 7.0 Crack

数学资源工作室 数学工作表生成器&#xff1a;快速轻松地创建数学工作表 使用易于使用的数学工作表生成器软件创建可打印的数学练习工作表。通过练习、谜题、问题等提高数学技能。 瞄准学习需求并激励学生 Math Resource Studio 是个性化数学教学的理想软件解决方案&#xff0c…

LeetCode279.Perfect-Squares<完全平方数>

题目&#xff1a; 思路&#xff1a; 这一题和硬币那题有一点像。 (13条消息) LeetCode322.Coin-Change&#xff1c;零钱兑换&#xff1e;_Eminste的博客-CSDN博客 所以我们初始化一系列“硬币”&#xff08;平方数&#xff09; 然后扫描用多少个“硬币”可以组成值。 最后返…

【ICCV2023】Scale-Aware Modulation Meet Transformer

Scale-Aware Modulation Meet Transformer, ICCV2023 论文&#xff1a;https://arxiv.org/abs/2307.08579 代码&#xff1a;https://github.com/AFeng-x/SMT 解读&#xff1a;ICCV2023 &#xff5c; 当尺度感知调制遇上Transformer&#xff0c;会碰撞出怎样的火花&#xff1…

C# 复习笔记

文章目录 Visual C# Step By StepC# 7.0核心技术指南面向对象是怎样工作的 Visual C# Step By Step 1.Net FrameWork&#xff1a;为开发应用程序而创建的一个平台&#xff08;可以是运行在windows &#xff0c;也可以是运行在其他操作系统&#xff09;。例如Mono&#xff0c;它…

第119天:免杀对抗-二开CSShellcode函数修改生成模版修改反编译重打包(下)

知识点 #知识点&#xff1a; 1、CS-表面特征消除 2、CS-HTTP流量特征消除 3、CS-Shellcode特征消除#章节点&#xff1a; 编译代码面-ShellCode-混淆 编译代码面-编辑执行器-编写 编译代码面-分离加载器-编写 程序文件面-特征码定位-修改 程序文件面-加壳花指令-资源 代码加载面…

C语言-print字符串打印-转义字符妙用

这里有两个有关打印的小知识 打印的字符串内容由两部分组成&#xff1a;可见字符、转义字符&#xff1b;各种字母、数字、以及空格&#xff0c;均属于可见字符&#xff0c;“\”等属于转义字符 举例&#xff1a; 1.直接print里面打印内容&#xff0c;内容直接出现 2.这里想将一…

iptable防火墙

主要作用&#xff1a; 隔离功能&#xff0c;在工作中&#xff0c;防火墙 的主要作用决定哪些数据可以被外网访问以及哪些数据可以进入内网访问 一般部署在网络边缘或者主机边缘&#xff0c;作用于网络层 安全技术&#xff1a; 1、入侵检测系统&#xff1a; 检测病毒、木马&a…