ThreadPoolExecutor 介绍

简介: ThreadPoolExecutor 介绍

线程池能够带来3个好处:

降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗;

提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行;

提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

 

超过可容纳任务数后,按策略处理

可容纳任务数 = 最大线程数(maximumPoolSize)+ 最大队列数(workQueue.size())

 

 

线程资源必须通过线程池提供, 不允许在应用中自行显式创建线程。

说明: 线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销, 解决资源不足的问题。如果不使用线程池, 有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换” 的问题。

线程池不允许使用 Executors 去创建, 而是通过 ThreadPoolExecutor 的方式, 这样的处理方式让写的同学更加明确线程池的运行规则, 规避资源耗尽的风险。

说明: Executors 返回的线程池对象的弊端如下:

1) FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE, 可能会堆积大量的请求, 从而导致 OOM。

2) CachedThreadPool:允许的创建线程数量为 Integer.MAX_VALUE, 可能会创建大量的线程, 从而导致 OOM。

3) ScheduledThreadPool:允许的请求队列长度为 Integer.MAX_VALUE, 可能会堆积大量的请求, 从而导致 OOM。

CPU核数可以通过 Runtime.getRuntime().availableProcessors() 获得

/** 
 *
 * @param corePoolSize 核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true。CPU核数+1
 * @param maximumPoolSize 线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效。 CPU核数*2+1
 * @param keepAliveTime 非核心线程的闲置超时时间,超过这个时间就会被回收。 
 * @param unit 指定keepAliveTime的单位,如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
 * @param workQueue 线程池中的任务队列.常用的有三种队列
 *  a.SynchronousQueue:是一种无缓冲的等待队列,在某次添加元素后必须等待其他线程取走后才能继续添加;
 *  b.LinkedBlockingDeque:是一个无界缓存的等待队列,不指定容量则为Integer最大值,锁是分离的;
 *  c.ArrayBlockingQueue:是一个有界缓存的等待队列,必须指定大小,锁是没有分离的;
 * @param threadFactory 线程工厂,提供创建新线程的功能,通过线程工厂可以对线程的一些属性进行定制。
 * @param handler 当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法,线程池有以下四种拒绝策略。
 *  a.AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出RejectedExecutionException 异常。会有日志出来。正常可以用这个
 *  b.CallerRunsPolicy:当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中run被拒绝的任务。 运行出来的进程名是 main
 *  c.DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务(丢弃队列最前面的任务),然后将被拒绝的任务添加到等待队列中。
 *  d.DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。没有日志输出,系统统无感
*/
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {}

 

线程池状态含义:

RUNNING:接受新任务并且处理阻塞队列里的任务;

SHUTDOWN:拒绝新任务但是处理阻塞队列里的任务;

STOP:拒绝新任务并且抛弃阻塞队列里的任务同时会中断正在处理的任务;

TIDYING:所有任务都执行完(包含阻塞队列里面任务)当前线程池活动线程为 0,将要调用 terminated 方法

TERMINATED:终止状态。terminated 方法调用完成以后的状态;

线程池状态转换:

RUNNING -> SHUTDOWN:显式调用 shutdown() 方法,或者隐式调用了 finalize(),它里面调用了shutdown()方法。

RUNNING or SHUTDOWN)-> STOP:显式 shutdownNow() 方法;

SHUTDOWN -> TIDYING:当线程池和任务队列都为空的时候;

STOP -> TIDYING:当线程池为空的时候;

TIDYING -> TERMINATED:当 terminated() hook 方法执行完成时候;

线程池的监控:

通过线程池提供的参数进行监控。线程池里有一些属性在监控线程池的时候可以使用

getTaskCount:线程池已经执行的和未执行的任务总数;

getCompletedTaskCount:线程池已完成的任务数量,该值小于等于 taskCount;

getLargestPoolSize:线程池曾经创建过的最大线程数量。通过这个数据可以知道线程池是否满过,也就是达到了maximumPoolSize;

getPoolSize:线程池当前的线程数量;

getActiveCount:当前线程池中正在执行任务的线程数量。

 

做几个计算

corePoolSize = 每秒需要多少个线程处理?

threadcount = tasks/(1/taskcost) =tasks*taskcout = (100~1000)*0.1 = 10~100 个线程。corePoolSize设置应该大于10根据8020原则,如果80%的每秒任务数小于200,那么corePoolSize设置为20即可

queueCapacity = (coreSizePool/taskcost)*responsetime 计算可得 queueCapacity = 20/0.1*1 = 200。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。

maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)  计算可得 maxPoolSize = (1000-200)/10 = 80(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数

rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理

keepAliveTime和allowCoreThreadTimeout采用默认通常能满足

以上关于线程数量的计算并没有考虑CPU的情况。若结合CPU的情况,比如,当线程数量达到60时,CPU达到100%,则将maxPoolSize设置为80也不合适,此时若系统负载长时间维持在每秒1000个任务,则超出线程池处理能力,应设法降低每个任务的处理时间(taskcost)。

目录
相关文章
|
存储 SQL 关系型数据库
(十三)MySQL引擎篇:半道出家的InnoDB为何能替换官方的MyISAM?
MySQL是一款支持拔插式引擎的数据库,在开发过程中你可以根据业务特性,从支持的诸多引擎中选择一款适合的,例如MyISAM、InnoDB、Merge、Memory(HEAP)、BDB(BerkeleyDB)、Example、Federated、Archive、CSV、Blackhole.....
389 2
|
运维 关系型数据库 MySQL
"MySQL运维精髓:深入解析数据库及表的高效创建、管理、优化与备份恢复策略"
【8月更文挑战第9天】MySQL是最流行的开源数据库之一,其运维对数据安全与性能至关重要。本文通过最佳实践介绍数据库及表的创建、管理与优化,包括示例代码。涵盖创建/删除数据库、表结构定义/调整、索引优化和查询分析,以及数据备份与恢复等关键操作,助您高效管理MySQL,确保数据完整性和系统稳定运行。
906 0
|
机器学习/深度学习 异构计算
50行代码搭建【自己的】文生图Web应用
50行代码搭建【自己的】文生图Web应用
2281 0
|
新零售 分布式计算 监控
云场景实践研究第40期:网聚宝
作为阿里云的深度用户,网聚宝的成长和阿里云的成长已经深深交织在了一起,在公开的5个产品技术上总投入资源大约是同类产品的1/5。作为一个中小规模的技术团队,客户已有3000多家品牌。本文将详细解读网聚宝在使用阿里云产品4年的过程中,基于云计算的架构心得。
2154 0
|
2天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1294 1
|
2天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
575 3
|
3天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
|
9天前
|
编解码 人工智能 自然语言处理
⚽阿里云百炼通义万相 2.6 视频生成玩法手册
通义万相Wan 2.6是全球首个支持角色扮演的AI视频生成模型,可基于参考视频形象与音色生成多角色合拍、多镜头叙事的15秒长视频,实现声画同步、智能分镜,适用于影视创作、营销展示等场景。
706 4