当前位置: 首页 > news >正文

浅谈Java线程池中的ThreadPoolExecutor工具类

 

目录

ThreadPoolExecutor的构造函数

 关于线程池的一些补充

线程池运行原理分析

概念原理解释

整个流程图如下:

一点补充


创建线程池主要有两种方式:

  • 通过Executor工厂类创建,创建方式比较简单,但是定制能力有限
  • 通过ThreadPoolExecutor创建,创建方式比较复杂,但是定制能力强

但我们一般不建议使用Executor工厂类来进行线程的创建。

原因如下:

Executor提供的很多方法默认使用的都是无界的LinkedBlockingQueue,在高负载情况下,无界队列很容易导致OOM——OOM 全称 “Out Of Memory”,表示内存耗尽。当 JVM 因为没有足够的内存来为对象分配空间,并且垃圾回收器也已经没有空间可回收时,就会抛出这个错误。

那么一旦出现了OOM,就会导致所有的请求都无法处理,这个是致命问题。所有要尽量避免使用无界队列——》即慎用Executor来创建线程

 

那么下面让我们详细了解推荐使用的ThreadPoolExecutor这个核心工具类。

ThreadPoolExecutor的构造函数


ThreadPoolExecutor 的构造函数非常复杂,如下面代码所示,这个最完备的构造函数有 7 个参数。
 

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

一起来看看这7个参数的含义分别是什么吧!

corePoolSize

核心线程数,就是该线程池保有的最下线程数

maximumPoolSize

最大线程数

keepAliveTime 和unit 

我们首先要知道线程分为空闲(阻塞等待中)和忙碌(执行任务)两种状态,当一个线程空闲了较长时间,同时此时线程池子中的线程数目大于核心线程数目corePoolSize,该线程就会被销毁回收

keepAlive和unit就是用来衡量空闲时间的,当空闲时间大于keepAliveTime时候(unit是keepAliveTime是时间单位),同时线程数目大于corePoolSize时,该线程就会被注销

workQueue

工作队列(一个阻塞队列,用来存放可执行任务Runnable Task)

threadFactory

通过这个参数你可以自己定义如何创建线程,比如你可以给线程指定一个有意义名称

handler

通过这个参数,你可以自定义任务的拒绝策略,如果线程池中的线程都在忙碌,并且工作队列也满了(前提工作队列是有界队列),此时当有一个新的任务添加进来,提交任务,线程池会拒绝接收。

至于拒绝的策略,你可以通过handler这个参数来指定,ThreadPoolExecutor以及提供了以下四种策略。

  • CallerRunsPolicy:提交任务的线程自己去执行该任务
  • AbortPolicy:默认的拒绝策略,会throw RejectedExecutorException—》这是个运行时异常,编辑器不强制catch、容易忽略,开发人员要谨慎使用(可以自己定义自己的拒绝策略)
  • DiscardPolicy:直接丢弃任务,没人任何异常输出
  • DiscardOldestPolicy:丢弃最古老的任务,,其实就是把最早进入任务队列workQueue的任务给丢弃掉,然后把新任务添加到任务队列中。

 关于线程池的一些补充

线程是一个重量级的对象,应该避免频繁创建和销毁

目前业界线程池的设计,普遍采用的都是生产者 - 消费者模式。


线程池的使用方是生产者,线程池本身是消费者

比如上面我们的任务队列workQueue(生产的Runnable任务就放到了该队列中),这些任务供线程池中的线程执行(消费)

线程池运行原理分析

概念原理解释

1、创建一个线程池,当此时还没有任务提交的时候(阻塞队列workQueue为空的时候,此时默认线程池中是没有线程的,当然了,此时也可以调用prestartThread方法,来预先创建一个核心线程

 

2、当线程池里面还没有线程或者是线程池中存活的线程小于核心线程数corePoolSize的时候,每新提交一个任务,线程池就会专门创建一个新的线程来处理刚刚提交的任务(阻塞队列workQueue中的Runnable任务)。

此时线程池中的线程会一直存活着,即使线程是空闲的,甚至空闲时间超过了keepAliveTime ,线程也不会销毁(此时线程池中的线程小于核心线程数corePoolSize)    

那么这个时候线程就只能等任务队列中什么时候有可执行的任务了(Runnable task) ,才会重写开始执行(变得忙碌起来,在此之前,线程一直是阻塞在那里的——》这也是为什么线程池队列用的是阻塞队列)

3、当线程池中的线程数等于线程核心数corePoolSize,同时任务队列有空间,此时当再有新的任务提交的时候,该任务会被放到任务队列中(workQueue)排队等待执行。而不会在新创建一个线程来执行刚刚提交的任务。

此时之前创建的线程并不会被注销,而是会不断的去拿阻塞队列中的任务,当任务队列中的任务为空的时候,线程会阻塞,直到有任务(Runnable Task)被放进任务队列中。

这也是为什么线程池的任务队列需要是阻塞队列。

我们之前说过Java中的线程池是生产者消费者模型,线程的使用方——》生产可运行的任务Runnable task,并且放到任务队列中)供线程池中的线程进行消费(任务的执行)

4、当线程池的线程数等于线程核心数corePoolsize,并且此时任务队列workQueue是满的状态。

这时如果来了新的Runnable Task,线程池子就会创建新的线程来处理该任务。

直到线程数达到了maximumPoolSize——》就不会再继续创建新的线程来处理任务了。

这些新的线程在执行完了当前的任务后,也不会被销毁。而是执行任务队列中的RunnableTask,(此时线程是忙碌状态,非空闲)当把任务队列中的任务执行完了后(此时线程池中线程数应该是大于corePoolSize的,那么接下来就会有一个判断逻辑——》判断线程是否需要被销毁,当线程因为任务队列为空,陷入阻塞(进入空闲状态)的时间大于keepAliveTime的时候,该线程就会被销毁——》直到线程数等于corePoolSize

5、如果线程池中的线程数目达到了maximumSize,并且此时任务队列也满了。

这种情况下还有新的任务过来,那就直接采用拒绝的处理器进行处理。默认的处理器逻辑是抛出一个RejectedExecutionException异常

整个流程图如下:

 

一点补充

使用线程池,还要注意异常处理的问题,例如通过 ThreadPoolExecutor 对象的 execute() 方法提交任务时,如果任务在执行的过程中出现运行时异常,会导致执行任务的线程终止;不过,最致命的是任务虽然异常了,但是你却获取不到任何通知,这会让你误以为任务都执行得很正常。虽然线程池提供了很多用于异常处理的方法,但是最稳妥和简单的方案还是捕获所有异常并按需处理

相关文章:

浅谈Java线程池中的ThreadPoolExecutor工具类

目录 ThreadPoolExecutor的构造函数 关于线程池的一些补充 线程池运行原理分析 概念原理解释 整个流程图如下&#xff1a; 一点补充 创建线程池主要有两种方式&#xff1a; 通过Executor工厂类创建&#xff0c;创建方式比较简单&#xff0c;但是定制能力有限通过ThreadPoo…...

分析过程:服务器被黑安装Linux RootKit木马

前言 疫情还没有结束&#xff0c;放假只能猫家里继续分析和研究最新的攻击技术和样本了&#xff0c;正好前段时间群里有人说服务器被黑&#xff0c;然后扔了个样本在群里&#xff0c;今天咱就拿这个样本开刀&#xff0c; 给大家研究一下这个样本究竟是个啥&#xff0c;顺便也给…...

运动型蓝牙耳机推荐哪款、最新运动蓝牙耳机推荐

提起运动耳机&#xff0c;如今很多运动爱好者和职业教练员们&#xff0c;都会向萌新推荐骨传导运动耳机。骨传导耳机解决了入耳式蓝牙耳机掉落的问题&#xff0c;佩戴相当舒服。骨传导耳机在佩戴过程中解放了双耳&#xff0c;不会因为耳机堵住耳朵&#xff0c;听不到环境音&…...

Python爬虫(9)selenium爬虫后数据,存入mongodb实现增删改查

之前的文章有关于更多操作方式详细解答&#xff0c;本篇基于前面的知识点进行操作&#xff0c;如果不了解可以先看之前的文章 Python爬虫&#xff08;1&#xff09;一次性搞定Selenium(新版)8种find_element元素定位方式 Python爬虫&#xff08;2&#xff09;-Selenium控制浏览…...

gulimall技术栈笔记

文章目录1.项目背景1.1电商模式1.2谷粒商城2.项目架构图3.项目技术&特色4.项目前置要求5.分布式基础概念5.1微服务5.2集群&分布式&节点5.3远程调用5.4负载均衡5.5服务注册/发现&注册中心5.6配置中心5.7服务熔断&服务降级5.7.1服务熔断5.7.2服务降级5.8API网…...

vue3生命周期钩子以及使用方式

按照生命周期的顺序来排列&#xff1a; onBeforeMount() DOM挂载前调用 注册一个钩子&#xff0c;在组件被挂载之前被调用。 当这个钩子被调用时&#xff0c;组件已经完成了其响应式状态的设置&#xff0c;但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。 onMount(…...

以假乱真的手写模拟器?

前些时候给大家推荐了一款word插件叫做“不坑盒子”&#xff0c;这款盒子不仅方便了word的操作&#xff0c;还附带了手写模拟器这样的效果只是在使用的时候不仅需要手动下载字体&#xff0c;而且效果也并不是太理想。 今天小编找到了一款软件--手写模拟器&#xff0c;不仅一键生…...

每日一题——L1-069 胎压监测(15)

L1-069 胎压监测 分数 15 小轿车中有一个系统随时监测四个车轮的胎压&#xff0c;如果四轮胎压不是很平衡&#xff0c;则可能对行车造成严重的影响。 让我们把四个车轮 —— 左前轮、右前轮、右后轮、左后轮 —— 顺次编号为 1、2、3、4。本题就请你编写一个监测程序&#…...

17_FreeRTOS事件标志组

目录 事件标志组 事件标志组与队列、信号量的区别 事件标志组相关API函数介绍 实验源码 事件标志组 事件标志位:用一个位,来表示事件是否发生 事件标志组是一组事件标志位的集合,可以简单的理解事件标志组,就是一个整数。 事件标志组的特点: 它的每一个位表示一个事件(…...

美团前端常考手写面试题总结

实现观察者模式 观察者模式&#xff08;基于发布订阅模式&#xff09; 有观察者&#xff0c;也有被观察者 观察者需要放到被观察者中&#xff0c;被观察者的状态变化需要通知观察者 我变化了 内部也是基于发布订阅模式&#xff0c;收集观察者&#xff0c;状态变化后要主动通知观…...

MyBatis基于XML的详细使用——动态sql

目录 动态sql if where trim foreach choose、when、otherwise set bind sql MyBatis常用OGNL表达式 动态sql 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQL 语句有多痛苦&#xff0c;例如…...

CMake编译opencv4.6

openCV系列文章目录 文章目录openCV系列文章目录前言一、准备工作二、使用步骤1.使用CMake编译openCV总结前言 最近在项目中遇到图片处理&#xff0c;一拍脑袋就想到大名鼎鼎的opencv 一、准备工作 1.openCV官网下载 2.CMake官方下载 3.vs2019官方下载 二、使用步骤 1.使用…...

数据分片(mycat)

1. 数据分片概念&#xff1a; 1.1. 分库分表 什么是分库分表&#xff1a; 将存放在一台数据库服务器中的数据&#xff0c;按照特定方式&#xff08;指的是程序开发的算法&#xff09;进行拆分&#xff0c;分散存放到多台数据库服务器中&#xff0c;以达到分散单台服务器负载的…...

基于STM32设计的倒车雷达系统(超声波模块多方位测距应用)

一、项目背景 汽车高科技产品家族中,专为倒车泊位设置的“倒车雷达”应运而生,倒车雷达的加装可以解决驾驶人员的后顾之忧,大大降低到车事故的发生。汽车倒车雷达全称为“倒车防撞雷达”,也叫“泊车辅助装置”,是汽车泊车安全辅助装置,能以声音或者更为直观的显示来告知…...

Robot Framework + Selenium2Library环境下,结合Selenium Grid实施分布式自动化测试

最近一段时间&#xff0c;公司在推行自动化测试流程&#xff0c;本人有幸参与了自定义通用控件的关键字封装和脚本辅助编写、数据驱动管理、测试用例执行管理等一系列工具软件的研发工作&#xff0c;积累了一些经验&#xff0c;在此与大家做一下分享&#xff0c;也算是做一个总…...

洛谷——前缀和与差分

前缀和与差分 文章目录前缀和与差分应用总结前缀和截断数组思路代码最大加权矩形题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示思路代码差分海底高铁题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1提示思路代码改变数组元素思路代码应用总结 前缀和用来…...

离线内网环境部署更新问题记录

文章目录低级错误错误一 配置文件参数错误错误二 文件位置错误新遇到的错误其他遇到的问题经验教训低级错误 错误一 配置文件参数错误 在与现场实施人员沟通时&#xff0c;出现信息错位&#xff0c;实施人员发来的截图里的ip地址不是正在使用的ip地址&#xff08;机器c重装系…...

【Git】Git是什么?简单说说Git的工作机制?Git的常用命令有那些?

目录 一、Git是什么? 二、简单说说Git的工作机制&#xff1f; 三、Git的常用命令有那些&#xff1f; &#x1f49f; 创作不易&#xff0c;不妨点赞&#x1f49a;评论❤️收藏&#x1f499;一下 一、Git是什么? Git 是一个免费的、开源的分布式版本控制系统&#xff0c;可…...

《精通Spring4.x 企业应用开发实战》第1章 Spring概述

目录标题前言一、Spring带给我们什么二、Spring体系结构三、Spring4.0新特性核心容器的增强泛型依赖注入Map依赖注入Lazy延迟依赖注入List注入Conditional 注解CGLIB 代理类增强其他四、Spring 子项目总结前言 汇总&#xff1a;《精通Spring4.x 企业应用开发实战》 一、Spring带…...

【Spring Cloud Alibaba】003-Nacos 概述与单机搭建

【Spring Cloud Alibaba】003-Nacos 概述与单机搭建 文章目录【Spring Cloud Alibaba】003-Nacos 概述与单机搭建一、Nacos 概述0、新技术学习思路推荐1、什么是 Nacos2、架构图架构图架构图信息二、Nacos 单机搭建1、下载与启动下载地址编辑 startup.cmd 文件下面对两种模式的…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

SQL慢可能是触发了ring buffer

简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...

TJCTF 2025

还以为是天津的。这个比较容易&#xff0c;虽然绕了点弯&#xff0c;可还是把CP AK了&#xff0c;不过我会的别人也会&#xff0c;还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...