线程池的创建工作机制

2024-04-29 17:44
文章标签 线程 创建 机制 工作

本文主要是介绍线程池的创建工作机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

线程池的创建&&工作机制

      • 1、线程池的作用
      • 2、线程池的创建和使用
        • 2.1自己写线程池:
        • 2.2使用Java提供的或者第三方提供的
          • 2.2.1线程池的参数含义
          • 2.2.2线程池工作机制
          • 2.2.3线程池的参数如何设置
          • 2.2.4调试

1、线程池的作用

为什么需要线程池:

  1. 线程的管理比较复杂(比如什么时候新增线程、什么时候减少空闲线程)
  2. 任务存取比较复杂(什么时候接受任务、什么时候拒绝任务、保证多线程不抢到同一个任务)

线程池的作用:轻松管理线程、协调任务的执行过程

2、线程池的创建和使用

2.1自己写线程池:

线程池的实现是很麻烦的,有些大厂的面试题会要我们实现线程池,这个时候就可以根据线程池的作用来分析编写啦.(比如什么时候新增线程、什么时候减少空闲线程)

2.2使用Java提供的或者第三方提供的

不用自己写,如果是在Spring中,可以用ThreadPoolTaskExecutor配合Async注解来实现。(不太建议)
如果是在Java中,可以使用JUC并发编程包中的ThreadPoolExecutor来实现非常灵活地自定义线程池。

Java线程池有七大参数

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler
) 
2.2.1线程池的参数含义

怎么确定线程池参数?结合实际情况(实际业务场景和系统资源)来测试调整,不断优化、
回归到该系统中,考虑该系统最脆弱的环节(系统的瓶颈)在哪里?
现有条件:比如AI生成能力的并发是允许4个任务同时去执行,AI能力允许20个任务排队

int corePoolSize(核心线程数):正常情况下,系统应该能同时工作的线程数(随时就绪状态)
int maximumPoolSize(最大线程数):极限情况下,线程池可容纳的最多线程
long keepAliveTime(空闲线程存活时间):非核心线程在没有任务的情况下,过多久要删除,释放无用的资源
TimeUnit unit(空闲线程存活时间的单位):分钟、秒
BlockingQueue workQueue(工作队列):用于存放给线程执行的任务的队列,该队列应当设置长度,不能为无限队列,那样也会占用额外的资源
ThreadFactory threadFactory(线程工厂):控制每个线程的生成、线程的属性(比如线程名)
RejectedExecutionHandler handler(拒绝策略):任务队列满的时候,采取什么措施。抛异常?不抛异常?自定义策略?

资源隔离策略:比如重要的任务(VIP任务)一个队列,普通任务一个队列,保证这两个队列互不干扰

2.2.2线程池工作机制

这里有用例图解说版 和 流程图版的
用例图解说版:没那么直观,但也清晰,细节到位
流程图版:更清晰直观,当部分细节没有

推荐两个都看

用例图解说:

刚开始,没有任何的线程,也没有任何的任务:
在这里插入图片描述



来了一个任务,发现我们的员工还没有达到正式员工数(corePoolSize = 2),来一个员工直接处理这个任务
在这里插入图片描述



又来了一个任务,发现我们的员工还没有达到正式员工数(corePoolSize = 2),再来一个员工直接处理这个任务
在这里插入图片描述


又来了一个任务,但是我们正式员工数已经满了(当前线程数 = corePoolSize = 2),任务放到队列(最大长度 workQueue.size 是 2)里等待,而不是再加新员工。
在这里插入图片描述



又来了一个任务,但是我们的任务队列已经满了(当前线程数 > corePoolSize = 2,已有任务数 = 最大长度 workQueue.size = 2),新增线程(maximumPoolSize = 4)来处理新任务,而不是丢弃任务
在这里插入图片描述



已经到了任务 7,但是我们的任务队列已经满了、临时工也招满了(当前线程数 = maximumPoolSize = 4,已有任务数 = 最大长度 workQueue.size = 2),调用 RejectedExecutionHandler 拒绝策略来处理多余的任务。
在这里插入图片描述


如果当前线程数超过 corePoolSize(正式员工数),又没有新的任务给他,那么等 keepAliveTime 时间达到后,就可以把这个线程释放。

流程图:



2.2.3线程池的参数如何设置

现有条件:比如AI生成能力的并发是允许4个任务同时去执行,AI能力允许20个任务排队
int corePoolSize(核心线程数):正常情况下,可以设置为2-4
int maximumPoolSize(最大线程数):设置为极限情况<=4
long keepAliveTime(空闲线程存活时间):一般为秒级或分钟级
TimeUnit unit(空闲线程存活时间的单位):分钟、秒
BlockingQueue workQueue(工作队列):结合实际情况去设置,可以设置为20
RejectedExecutionHandler handler(拒绝策略):抛异常,标记数据库的任务状态为“任务满了已拒绝”

一般情况下,任务分为IO密集型和计算密集型两种
计算密集型:吃CPU,比如音视频处理、图像处理、数学计算等,一般设置corePoolSize为CPU核心数+1(空余线程),可以让每个线程都能利用好CPU的每个核,而且线程之间不用频繁切换
IO密集型:吃带宽/内存/硬盘等资源,corePoolSize可以设置大一些,一般为2n左右,但是建议以IO能力为主
例:导入百万数据到数据库属于IO密集型任务

2.2.4调试

自定义线程池:

@Configuration
public class ThreadPoolExecutorConfig {@Beanpublic ThreadPoolExecutor threadPoolExecutor() {ThreadFactory threadFactory = new ThreadFactory() {private int count = 1;@Overridepublic Thread newThread(@NotNull Runnable r) {Thread thread = new Thread(r);thread.setName("线程" + count);count++;return thread;}};ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 4, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), threadFactory);return threadPoolExecutor;}

提交任务到线程池:

@GetMapping("/add")
public void add(String name) {CompletableFuture.runAsync(() -> {System.out.println("任务执行中:" + name + ",执行人:" + Thread.currentThread().getName());try {Thread.sleep(60000);} catch (InterruptedException e) {e.printStackTrace();}},threadPoolExecutor);
}

这篇关于线程池的创建工作机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946735

相关文章

Elasticsearch系列---Elasticsearch的基本概念及工作原理

基本概念 Elasticsearch有几个核心的概念,花几分钟时间了解一下,有助于后面章节的学习。 NRT Near Realtime,近实时,有两个层面的含义,一是从写入一条数据到这条数据可以被搜索,有一段非常小的延迟(大约1秒左右),二是基于Elasticsearch的搜索和分析操作,耗时可以达到秒级。 Cluster 集群,对外提供索引和搜索的服务,包含一个或多个节点,每个节点属于

NVM安装及VUE创建项目的N种方式

VUE 参考官网:https://cli.vuejs.org/zh/guide/ 目录 NVM安装 1.卸载node.js 2.安装nvm ​编辑​ 3.配置 4.使用nvm安装node.js 5.nvm常用命令 创建VUE项目 1.使用vue init 创建vue2(不推荐) 2.使用vue create创建vue2和3(较推荐) 3.使用npm create vu

函数栈帧的创建和销毁(详细理解)

🎁个人主页:我们的五年 🔍系列专栏:c语言课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录  问题: 1.ebp,esp两个寄存器用来维护函数栈帧 2.main函数也一个函数,main函数也要被其他函数调用  3.函数栈帧创建的过程 4.函数栈帧的销毁过程    问题: 1.局部变量是怎么创建的? 调用函数的时候,会为函数开辟一块空间,然后第一个局

数字证书的工作原理

1 为什么需要数字证书         三方支付机构在和银联网联交互的时候,通常会使用数字证书进行加签验签,那么为什么要用数组证书呢。核心是要解决密钥传输被截获的问题,比如在非对称加密中,三方支付公司需要获取银联的公钥信息,但是如果请求被第三方拦截的话,公钥信息就可能被替换,会导致三方支付公司用第三方的公钥进行加密,交互信息存在泄露的风险(谁也不想自己的银行卡密码被泄露)。因此,引入证书,用于鉴

中断处理的工作队列机制

工作队列(work queue)是另外一种将工作推后执行的形式 ,它和我们前面讨论的所有其他形式都有不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。那么,什么情况下使用工作队列,什么情况下使用tasklet。如果推后执行的任务需要睡眠,那么就选择

中断处理的 tasklet 机制

中断处理的 tasklet 机制中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化。但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失。因此,Linux内核的目标就是尽可能快的处理完中断请求,尽其所能把更多的处理向后推迟。例如,假设一个数据块已经达到了网线,当中断控制器接受到这个中断请求信号时,Lin

android firmware下载机制

加载固件的方法: Linux 设备驱动的固件firmware加载 android 应用层 firmware文件要放入这三个目录之一: /etc/firmware/ /vendor/firmware/ /firmware/image/ 这里监听kernel发出的uevent(实际是监听netlink socket)。当收到uevent,根据名称在上面三个目录中寻找文件,找到文件后将文件传给k

.NET垃圾回收机制之迷-管理内存的秘密武器,提升应用性能的利器!

作为.NET开发者,很多人应该都听说过"垃圾回收器(Garbage Collector,GC)“。它就像一个清道夫,时刻在清理程序不再使用的内存空间。有人称它为"内存管理鬼斧神工”,有人也痛骂它"导致性能杀手"。那么,垃圾回收机制到底是何方神圣?今天我们就来一探其中的奥秘。 一、垃圾回收机制概述 GC是.NET运行时(CLR)的一部分,主要负责追踪和管理堆内存的内存分配和回收。它的

【JavaSE】反射机制-基础概述

Catalog JavaSE-反射机制-基础概述1. 应用场景2. 优点3. 缺点4. Class类解析5. 获取Class类实例的方式6. 反射机制是什么7. 反射机制原理图(老韩)8. 具体应用 JavaSE-反射机制-基础概述 1. 应用场景 常见的如下: 当获取到一个未知类型但是知道其中的方法名和方法参数的类对象时,可以通过反射机制调用这个方法,甚至于获取到这个类

2024最新互联网公司工作时长排行榜出炉!

“工作时长”,是选择公司的一个非常重要的参考指标。 我们在选择一个公司的时候,除了需要关注总收入package 以外,还需要考虑这家公司的加班时长是否人性化。 我们的工作时长是周工作小时数。法定工作时间是40小时(955)。大小周通常折算为周工作60小时, 996通常折算为周工作65小时。以此类推。排名依据最近一年公司薪酬数据中工作时长的平均数。 大概几年前,职级对标就在提交薪酬表单中增加了