【JUC】线程池ThreadPoolTaskExecutor与面试题解读
1、ThreadPoolTaskExecutor 创建线程池
从它的创建和使用说起,创建和使用的代码如下:
创建:
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.setThreadNamePrefix("ExecutorPool-");executor.initialize();return executor;
使用:
threadPoolTaskExecutor.execute(() -> {//do something...});
上面创建线程池使用的是ThreadPoolTaskExecutor ,点击进入executor.initialize()方法:
ExecutorConfigurationSupport.java
/*** Set up the ExecutorService.*/public void initialize() {if (logger.isInfoEnabled()) {logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));}if (!this.threadNamePrefixSet && this.beanName != null) {setThreadNamePrefix(this.beanName + "-");}this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);}
再进入initializeExecutor方法:
ThreadPoolTaskExecutor.java
/*** Note: This method exposes an {@link ExecutorService} to its base class* but stores the actual {@link ThreadPoolExecutor} handle internally.* Do not override this method for replacing the executor, rather just for* decorating its {@code ExecutorService} handle or storing custom state.*/@Overrideprotected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);ThreadPoolExecutor executor;if (this.taskDecorator != null) {executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,queue, threadFactory, rejectedExecutionHandler) {@Overridepublic void execute(Runnable command) {Runnable decorated = taskDecorator.decorate(command);if (decorated != command) {decoratedTaskMap.put(decorated, command);}super.execute(decorated);}};}else {executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,queue, threadFactory, rejectedExecutionHandler);}if (this.allowCoreThreadTimeOut) {executor.allowCoreThreadTimeOut(true);}this.threadPoolExecutor = executor;return executor;}
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveSeconds,TimeUnit.SECONDS,queue, threadFactory,rejectedExecutionHandler);
可以看到new ThreadPoolExecutor(),ThreadPoolTaskExecutor 本质是使用ThreadPoolExecutor,那为何要存在ThreadPoolTaskExecutor?
ThreadPoolTaskExecutor的方法基本都是围绕如何创建ThreadPoolExecutor,安全有效设置各种参数,添一些行为等。

如下面设置MaxPoolSize(最大线程池数),它考虑到并发同步、threadPoolExecutor 是否为null的问题。
ThreadPoolTaskExecutor.java
/*** Set the ThreadPoolExecutor's maximum pool size.* Default is {@code Integer.MAX_VALUE}.* <p><b>This setting can be modified at runtime, for example through JMX.</b>*/
public void setMaxPoolSize(int maxPoolSize) {synchronized (this.poolSizeMonitor) {this.maxPoolSize = maxPoolSize;if (this.threadPoolExecutor != null) {this.threadPoolExecutor.setMaximumPoolSize(maxPoolSize);}}
}
再如:
设置队列时,它会创建一个安全的队列,有合适大小的LinkedBlockingQueue或者没有大小的SynchronousQueue。从而避免使用newSingleThreadExecutor这类创建一个不安全的等待队列。
ThreadPoolTaskExecutor.java
/*** Create the BlockingQueue to use for the ThreadPoolExecutor.* <p>A LinkedBlockingQueue instance will be created for a positive* capacity value; a SynchronousQueue else.* @param queueCapacity the specified queue capacity* @return the BlockingQueue instance* @see java.util.concurrent.LinkedBlockingQueue* @see java.util.concurrent.SynchronousQueue*/
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {if (queueCapacity > 0) {return new LinkedBlockingQueue<>(queueCapacity);}else {return new SynchronousQueue<>();}
}
newSingleThreadExecutor方式创建的等待队列中的LinkedBlockingQueue容量是Integer.MAX_VALUE
Executors.java
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
LinkedBlockingQueue.java
public LinkedBlockingQueue() {this(Integer.MAX_VALUE);}
ThreadPoolTaskExecutor的父类ExecutorConfigurationSupport的方法可以设置BeanName、ThreadNamePrefix等。

总结来说在spring项目中使用ThreadPoolTaskExecutor创建线程池是首推使用的。
2、ThreadPoolExecutor解读
2.1 基本使用介绍
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveSeconds,TimeUnit.SECONDS,queue, threadFactory,rejectedExecutionHandler);
-
corePoolSize:线程池的核心线程数,定义了最小可以同时运行的线程数量。
-
maximumPoolSize:线程池的最大线程数。队列中存放的任务达到队列容量时,可以同时运行的线程数量变为最大线程数。
-
keepAliveTime:当线程池中的线程数量大于corePoolSize时,如果没有新任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了KeepAliveTime才会被回收销毁。
-
unit:keepAliveTime参数的时间单位,包括DAYS、HOURS、MINUTES、MILLISECONDS等。
-
workQueue:用于保存等待执行任务的阻塞队列。可以选择以下集个阻塞队列:
- ArrayBlockingQueue:是一个基于数组结构的阻塞队列,此队列按FIFO原则对元素进行排序;
- LinkedBlockingQueue:是一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通常高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列;
- SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量常高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool()使用了这个队列;
- PriorityBlockingQueue:一个具有优先级的无限阻塞队列;
-
threadFactory:用于设置创建线程的工厂,可以通过工厂给每个创造出来的线程设置更有意义的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字:new ThreadFactoryBuilder().setNameFormat(“XX-task-%d”).build();7)handler:饱和策略。若当前同时运行的线程数量达到最大线程数量并且队列已经被放满,ThreadPoolExecutor定义了一些饱和策略:
- ThreadPoolExecutor.AbortPolicy:直接抛出RejectedExecutionException异常来拒绝处理新任务;
- ThreadPoolExecutor.CallerRunsPolicy:只用调用者所在的线程来运行任务,会降低新任务的提交速度,影响程序的整体性能;
- ThreadPoolExecutor.DiscardPolicy:不处理新任务,直接丢弃掉;
- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列中最近的一个任务,执行当前任务;
处理流程:

1.在创建了线程池之后,等待提交过来的任务请求
2.当调用execute()方法添加一个请求任务的时候,线程池会做出如下判断:
2.1 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个程序
2.2 如果正在运行的线程数量大于或者等于corePoolSize,那么将这个任务放入队列
2.3 如果这个时候队列满了并且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻执行这个任务
2.4 如果队列满了并且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行
3. 当一个线程完成任务的时候,它会从队列中取下一个任务来执行
4. 当一个线程无事可做超过一定时间(keepAliveTime)时:线程会判断如果当前运行的线程数大于corePoolSize,那么这个线程就会被停掉。
最经典的比喻是银行办理业务,可以很形象的去理解线程池七个核心参数之间的关系:

银行刚开始上班,然后又一位需要办理业务的顾客1进来,柜员1就来一个帮这位顾客1办理,其他在吃早餐摸鱼。这位顾客1办理完了业务就走了,柜员1坐在柜台上静等。
这时又有一位顾客2过来,这时不是柜员1去接待,而是叫上柜员2,因为这天安排上班的两位柜员(corePoolSize=2)。
顾客3来办理业务,因为上班的柜员已经全部就位了,柜员1有空,柜员1就去接待顾客3。
顾客4来办理业务,因为柜员1和柜员2都在忙,所以顾客4在凳子上静等。柜员2帮顾客2办理完了,就去给顾客4办理。这时凳子又空出3张(Queue容量为3)。
顾客5、顾客6、顾客7同时过来,柜员1和柜员2都在忙,顾客5、顾客6、顾客7就坐满了凳子。
过了一会,顾客8来了,柜员1和柜员2在忙同时没有凳子坐了,本着顾客就是上帝的原则,打电话叫来一个在休息的柜员3帮顾客8办理业务。
生意兴隆,顾客9来了,打电话叫来一个在休息的柜员4帮顾客9办理业务。
这是顾客10来了,一进门,柜员没有了,连休息中的也没有了(maximumPoolSize=4),银行直接赶走他。
过了一段时间,银行的客户都办完业务走了,那两位本来应该休息的柜员说:我们再等一下(keepAliveTime),不忙了我们就撤了。
看上面的场景中,搬救兵请休息中的柜员回来干活是很麻烦的,要先坐满凳子再说。线程池中也是,要等等待队列满了以后才会去创建核心线程数之外的线程,因为创建线程的花销是很大的。
相关文章:
【JUC】线程池ThreadPoolTaskExecutor与面试题解读
1、ThreadPoolTaskExecutor 创建线程池 从它的创建和使用说起,创建和使用的代码如下: 创建: ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor();executor.setCorePoolSize(corePoolSize);executor.setMaxPoolSize(maxPoolSize…...
也许你正处于《孤注一掷》中的“团队”,要留心了
看完这部电影,心情久久不能平静,想了很多,倒不是担心自己哪天也成为“消失的yaozi”,而是在想,我们每天所赖以生存的工作,跟电影里他们的工作比,差别在哪里呢? 目录 1. 产品的本质…...
Kafka 入门到起飞 - 什么是 HW 和 LEO?何时更新HW和LEO呢?
上文我们已经学到, 一个Topic(主题)会有多个Partition(分区)为了保证高可用,每个分区有多个Replication(副本)副本分为Leader 和 Follower 两个角色,Leader副本对外提供读…...
go入门实践五-实现一个https服务
文章目录 前言生成证书申请免费的证书使用Go语言生成自签CA证书 https的客户端和服务端服务端代码客户端代码 tls的客户端和服务端服务端客户端 前言 在公网中,我想加密传输的数据。(1)很自然,我想到了把数据放到http的请求中,然后通过tls确…...
面试之快速学习STL-set
set 和 map、multimap 容器不同,使用 set 容器存储的各个键值对,要求键 key 和值 value 必须相等使用 set 容器存储的各个元素的值必须各不相同从语法上讲 set 容器并没有强制对存储元素的类型做 const 修饰, 即 set 容器中存储的元素的值是可以修改的。…...
leetcode 1614.括号的最大嵌套深度
⭐️ 题目描述 🌟leetcode链接:括号的最大嵌套深度 ps: 使用数据结构栈来存储 ( 在使用 maxDepth 变量记录栈顶 top 的最大值,当遇到 ) 时删除栈顶元素。举个例子 (1)((2))(((3))),当遇到第一个 ( 时 top 1ÿ…...
Ajax 笔记(四)—— Ajax 进阶
笔记目录 4. Ajax 进阶4.1 同步代码和异步代码4.2 回调函数地狱4.2.1 解决方法一:Promise 链式调用4.2.2 解决方法二:async 函数和 await 4.3 Promise.all 静态方法4.4 事件循环4.4.1 事件循环4.4.2 宏任务与微任务 4.5 案例4.5.1 案例一-商品分类4.5.2 …...
Linux 5种网络IO模型
Linux IO模型 网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作。刚才说了,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操…...
Linux多线程【初识线程】
✨个人主页: 北 海 🎉所属专栏: Linux学习之旅 🎃操作环境: CentOS 7.6 阿里云远程服务器 文章目录 🌇前言🏙️正文1、什么是线程?1.1、基本概念1.2、线程理解1.3、进程与线程的关系…...
Python爬虫的应用场景与技术难点:如何提高数据抓取的效率与准确性
作为专业爬虫程序员,我们在数据抓取过程中常常面临效率低下和准确性不高的问题。但不用担心!本文将与大家分享Python爬虫的应用场景与技术难点,并提供一些实际操作价值的解决方案。让我们一起来探索如何提高数据抓取的效率与准确性吧…...
Spring Cloud Gateway系例—参数配置(CORS 配置、SSL、元数据)
一、CORS 配置 你可以配置网关来控制全局或每个路由的 CORS 行为。两者都提供同样的可能性。 1. Global CORS 配置 “global” CORS配置是对 Spring Framework CorsConfiguration 的URL模式的映射。下面的例子配置了 CORS。 Example 77. application.yml spring:cloud:gat…...
QT:UI控件(按设计师界面导航界面排序)
基础部分 创建新项目:QWidget,QMainWindow,QDialog QMainWindow继承自QWidget,多了菜单栏; QDialog继承自QWidget,多了对话框 QMainWindow 菜单栏和工具栏: Bar: 菜单栏:QMenuBar࿰…...
AtCoder Beginner Contest 314-A/B/C
A - 3.14 题目要求输出圆周率保留小数几位后的结果 用字符串来存储长串的圆周率,截取字符串就可以了。 #include<iostream> using namespace std; int main() {string s"3.1415926535897932384626433832795028841971693993751058209749445923078164062…...
讯飞星火、文心一言和通义千问同时编“贪吃蛇”游戏,谁会胜出?
同时向讯飞星火、文心一言和通义千问三个国产AI模型提个相同的问题: “python 写一个贪吃蛇的游戏代码” 看哪一家AI写的程序直接能用,谁就胜出! 讯飞星火 讯飞星火给出的代码: import pygame import sys import random# 初…...
数学建模之“聚类分析”原理详解
一、聚类分析的概念 1、聚类分析(又称群分析)是研究样品(或指标)分类问题的一种多元统计法。 2、主要方法:系统聚类法、有序样品聚类法、动态聚类法、模糊聚类法、图论聚类法、聚类预报法等。这里主要介绍系统聚类法…...
【面试问题】当前系统查询接口需要去另外2个系统库中实时查询返回结果拼接优化思路
文章目录 场景描述优化思路分享资源 场景描述 接口需要从系统1查询数据,查出的每条数据需要从另一个系统2中再去查询某些字段, 比如:从系统1中查出100条数据,每条数据需要去系统2中再去查询出行数据,可能系统1一条数…...
Scada和lloT有什么区别?
人们经常混淆SCADA(监督控制和数据采集)和IIoT(工业物联网)。虽然SCADA系统已经存在多年,但IIoT是一种相对较新的技术,由于其能够收集和分析来自各种设备的大量数据而越来越受欢迎。SCADA和IIoT都用于提高工…...
Conda(Python管理工具)
1.简介 Conda是一个开源的包管理器和环境管理器,主要用于管理Python,但也可以用于其他语言。它主要用于安装、管理和更新软件包及其依赖项,以及创建、保存、加载和切换不同的开发环境。Conda可以在Windows、MacOS和Linux系统上使用ÿ…...
(14)嵌套列表,Xpath路径表达式,XML增删查改,Implicit,Operator,Xml序列化,浅拷贝与深拷贝
一、作业问题 1、问:listbox1.items[i]返回的object是指的字符串吗? 答:items是真正的对象集合,在Add时加的是Person对象p,则里面的item就是Person对象p。 但是,在listbox1显…...
软考笔记 信息管理师 高级
文章目录 介绍考试内容与时间教材 预习课程一些例子课本结构考试内容 1 信息与信息化1.1 信息与信息化1.1.1 信息1.1.2 信息系统1.1.3 信息化 1.2 现代化基础设施1.2.1 新型基础建设1.2.2 工业互联网1.2.3 车联网: 1.3 现代化创新发展1.3.1 农业农村现代化1.3.2 两化…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
Mac flutter环境搭建
一、下载flutter sdk 制作 Android 应用 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 1、查看mac电脑处理器选择sdk 2、解压 unzip ~/Downloads/flutter_macos_arm64_3.32.2-stable.zip \ -d ~/development/ 3、添加环境变量 命令行打开配置环境变量文件 ope…...
深入理解 React 样式方案
React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...
