线程池、及Springboot线程池实践

摘要

本文介绍了线程池基本概念、线程及线程池状态、java中线程池提交task后执行流程、Executors线程池工具类、最后介绍在springboot框架下使用线程池和定时线程池,以及task取消

线程池基本

背景

线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务

线程池优势

  • 降低执行task重复创建销毁线程的消耗
  • 提高执行task响应速度。切换到task时,无需创建线程,直接将task“挂”到线程执行

线程状态

线程共有6个状态,分别是new、runnable、waiting、time_waiting、blocked、terminal。其中runnable状态包括running、ready。且runnable和waiting、time_waiting、blocked、terminal之间切换。

new

线程实例化初始状态

RUNNABLE(running、ready)

running:正在运行

ready:running状态线程占用cpu时间片完(主动调用yield)后状态。

yield():向调度程序提示当前线程愿意放弃cpu的使用,调度程序可以忽略此提示。很少使用,可用于调试,它可能有助于重现由于竞争条件而产生的错误。

waiting

等待状态,例如调用wait、join、park方法,线程等待

time_waiting

限时等待,例如调用sleep(time),wait(time),join(time),parkNanos(),parkUntil(thread)

blocked

阻塞状态,例如等待锁,或等待进入synchronized块

terminal

线程终止

线程池状态

RUNNING

可接收新提交的任务,可处理队列中任务。

SHUTDOWN

不再接收新提交的任务,但是可处理队列中的任务。

STOP

不再接收新提交的任务,且不再处理队列中的任务。

TIDYING

所有任务已经被终结,工作线程数为0,该状态会执行钩子函数terminated()

TERMINATED

已执行完毕terminated()方法。

状态转换

RUNNING -> SHUTDOWN:调用shutdown()方法后。

(RUNNING or SHUTDOWN) -> STOP:调用shutdownNow()方法后。

SHUTDOWN -> TIDYING:当队列中任务为空,线程池中任务为空。

TIDYING -> TERMINATED:terminated()钩子方法执行完毕之后。

Java线程池实践

ThreadPool参数

corePoolSize,maximumPoolSize,workQueue,keepAliveTime,TimeUnit,threadFactory,RejectedExecutionHandler

核心线程数

corePoolSize:线程池中存活线程数量,除非allowCoreThreadTimeOut=true时会被kill

最大线程数

maximumPoolSize:线程池允许最大线程数,达到keepAliveTime后会被kill

等待时间和单位

keepAliveTime:多于核心线程之外的线程,超过该时间的线程会被kill

TimeUnit:keepAliveTime时间单位

阻塞队列

workQueue:保存未执行的Runnable 的task

线程工厂

threadFactory:创建线程的工厂类,默认Executors.defaultThreadFactory()

拒绝策略

RejectedExecutionHandler:因队列满、且超过最maxThreadPool限制的task处理策略

  • AbortPolicy:拒绝task,抛出RejectedExecutionException 。是ThreadPoolExecutor和ScheduledThreadPoolExecutor的默认拒绝策略
  • DiscardPolicy:丢弃task,无异常
  • DiscardOldestPolicy:丢弃未处理的最old的task,无异常
  • CallerRunsPolicy:拒绝task,抛回给提交task的线程执行
    static volatile int  count = 0;public static void main(String[]args){
//可接纳6+1=7个任务,再多则会执行默认拒绝策略ThreadPoolExecutor executor = new ThreadPoolExecutor(5,6,1000l, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1));Runnable task = new Runnable() {@Overridepublic void run() {System.out.println(count++);try {Thread.sleep(1000000000l);} catch (InterruptedException e) {throw new RuntimeException(e);}}};for(int i=0;i<8;i++){executor.execute(task);//抛出RejectedExecutionException}System.out.println(executor.getActiveCount());}

Task提交流程

coreThread  --  queue -- maxThread -- handler

  • 若运行线程少于corePoolSize,尝试以给task启动一个新的core线程
  • task进入BlockQueue排队
  • BlockQueue已满,添加新线程。失败则拒绝该task,执行拒绝策略

Thread回收

回收逻辑:Runnable状态线程数ctl减1;从工作线程HashSet中移除工作线程Worker对象

  • 回收超过keepAliveTime之外的非core线程
  • 回收超过keepAliveTime的core线程,且allowCoreThreadTimeOut=true

 线程池任务管理

获取活跃线程数

ThreadPoolExecutor.getActiveCount()。线程池中正在运行的线程个数,包括核心线程+队列满后新建的非核心线程

static volatile int  count = 0;public static void main(String[]args) throws InterruptedException {ThreadPoolExecutor executor = new ThreadPoolExecutor(5,9,1000l,TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(1));Runnable task = new Runnable() {@Overridepublic void run() {System.out.println(count++);try {Thread.sleep(1000000000l);} catch (InterruptedException e) {throw new RuntimeException(e);}}};for(int i=0;i<8;i++){executor.execute(task);}
//输出为7:5个在核心线程,1个在队列,2个为新建线程System.out.println("活跃线程:"+executor.getActiveCount());}

获取提交的task状态

ThreadPoolExecutor.getTaskCount():历史提交的task总数

ThreadPoolExecutor.getCompletedTaskCount():已完成task个数

取消任务

futrure.cancel()

task提交后状态

  • 线程未启动
  • 线程正在执行
  • 线程已结束

task未启动,cancel后会从线程池的阻塞队列中remove掉task;

task已结束,cancel对task不会有任何影响

task正在执行:通过interrupted标志位,在sleep/join/wait处抛出中断异常终止task执行

无future第三方库

 该场景适用于调用第三方库无future返回值情况。可以通过在第三方库中例如cancelTask等方法中重写Future.cancel()取消task

Java Executors线程池工具

Executors是java一个线程池工具,便捷创建例如单个、固定数量、定时等特征的线程池。不同特征的线程池,其参数不同。

newSingleThreadPool

适用于提交的任务按顺序执行场景:核心线程数=最大线程数=1,一直存活,如果任务异常中断了线程,则创建一个新线程;使用链表阻塞无界队列;默认线程工厂Executors.defaultThreadFactory();默认阻塞策略:AbortPolicy

短期提交任务过多,则队列溢出,内存溢出

    public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}

cachedThreadPool

适用于执行许多短期(60s)异步任务场景:核心线程为0,最大线程为Integer.MAX_VALUE,存活60s,使用同步队列SynchronousQueue;默认线程工厂Executors.defaultThreadFactory();默认阻塞策略:AbortPolicy

短期提交任务过多,则一直创建线程,内存溢出

SynchronousQueue(同步队列):队列中不存储元素,元素的offer和take阻塞对应 

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}

newFixedThreadPool

适用于执行IO较少异步任务场景:核心线程=最大线程=输入参数,线程创建后不回收,使用LinkedBlockingQueue阻塞无界队列;默认线程工厂Executors.defaultThreadFactory();默认阻塞策略:AbortPolicy

短期提交任务过多,则队列溢出,内存溢出

   public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}

newThreadScheduledExecutor

适用于单一定时任务:核心线程数=1,最大线程数=Integer.MAX_VALUE,一直存活,使用优先级队列DelayedWorkQueue定时,默认线程工厂Executors.defaultThreadFactory();默认阻塞策略:AbortPolicy

 DelayedWorkQueue优先级队列,底层使用“堆”数据结构实现

ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());}

SpringBoot线程池

SpringBoot线程池在JUC包下ThreadPoolExecutor基础上进行封装,通过注入Bean或注解的方式使用。SpringBoot提供的线程池包括普通提交task的线程池和定时线程池。

提交task方式

通过@Configuration注解和@Bean注解,注入定义的ThreadPoolTaskExecutor对象,通过@Autowired注入使用的threadPoolTaskExecutor对象,通过threadPoolTaskExecutor的submit()或execute()方法提交任务。

注意:@Autowired注入@Bean注解对象时,默认是@Bean对象的方法名

@Configuration
public class TaskThreadPoolConfig {
//将线程池注入Spring IOC@Beanpublic ThreadPoolTaskExecutor threadPoolTimeoutExecutor() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}//注入线程池对象@AutowiredThreadPoolTaskExecutor threadPoolTimeoutExecutor;//提交任务
public void test(){threadPoolTimeoutExecutor.submit(()->{runTask();});}
}

注解方式

通过@Configuration注解和@Bean注解,注入定义的ThreadPoolTaskExecutor对象,通过@Async注解异步执行方法,方法可以返回task的Future句柄,或返回void

注意:@Bean注解可以添加线程池名字,异步方法@Async可以指定线程池名字

@Configuration
public class TaskThreadPoolConfig {@Bean(value = "test-threadpool")//定义线程池名public ThreadPoolTaskExecutor threadPoolTimeoutExecutor() {ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();threadPoolTaskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2);threadPoolTaskExecutor.initialize();return threadPoolTaskExecutor;}//方法上添加注解,该方法异步执行,方法可以返回Future任务句柄,或void@Async(value = "test-threadpool")//指定线程池public Future<Object> runTask(){System.out.println("--");return new AsyncResult<>(true);}
}

取消任务

获取task的Future句柄,通过future.cancel(true)取消任务。其内部则通过翻转interrupted标志位,遇到例如sleep、wait、join等则抛出中断异常,终止执行task的线程。

	@AutowiredThreadPoolTaskExecutor threadPoolTimeoutExecutor;public static void main(String []args){Future<?> future = threadPoolTimeoutExecutor.submit(()->{try {Thread.sleep(1000l);} catch (InterruptedException e) {throw new RuntimeException(e);}});if(!future.isDone()){//task未结束future.cancel(true);//翻转执行task的线程的中断标志位,遇到例如sleep,join,wait等抛出中断异常终止task}}

觉得不错,点个👍吧,😄

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

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

相关文章

人工智能学习7(决策树算法)

编译工具&#xff1a;PyCharm 文章目录 编译工具&#xff1a;PyCharm 决策树算法信息熵信息熵例题计算&#xff1a; 信息增益&#xff08;决策树划分依据之一ID3&#xff09;信息增益例题计算&#xff1a; 信息增益率(决策树划分依据之一C4.5)基尼值和基尼指数(决策树划分依据之…

每日3道PWN(第一天)

环境准备 我现在用的是kali 现阶段工具&#xff1a;checkesc、IDA、比较完善的python环境 下载工具的话&#xff0c;我这里不提供了 buuctf——test_your_nc1 参考wp&#xff1a; BUUCTF PWN-----第1题:test_your_nc_buuctf test_your_nc-CSDN博客 查看的资料&#xff1a;…

合并两个有序链表[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#…

软著项目推荐 深度学习的口罩佩戴检测 - opencv 卷积神经网络 机器视觉 深度学习

文章目录 0 简介1 课题背景&#x1f6a9; 2 口罩佩戴算法实现2.1 YOLO 模型概览2.2 YOLOv32.3 YOLO 口罩佩戴检测实现数据集 2.4 实现代码2.5 检测效果 3 口罩佩戴检测算法评价指标3.1 准确率&#xff08;Accuracy&#xff09;3.2 精确率(Precision)和召回率(Recall)3.3 平均精…

使用coco数据集进行语义分割:数据预处理与损失函数

如何coco数据集进行目标检测的介绍已经有很多了&#xff0c;但是关于语义分割几乎没有。本文旨在说明如何处理 stuff_train2017.json stuff_val2017.json panoptic_train2017.json panoptic_val2017.json&#xff0c;将上面那些json中的dict转化为图片的label mask&am…

BUUCTF 小易的U盘 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 小易的U盘中了一个奇怪的病毒&#xff0c;电脑中莫名其妙会多出来东西。小易重装了系统&#xff0c;把U盘送到了攻防实验室&#xff0c;希望借各位的知识分析出里面有啥。请大家加油噢&#xff0c;不过他特别关照&a…

【C++ STL】vector类最全详解(什么是vector?vector类的常用接口有哪些?)

目录 一、前言 二、什么是vector ? &#x1f4a6; vector的基本概念 &#x1f4a6;vector的作用是什么 &#x1f4a6;总结 三、 vector的(一维)定义 四、vector(一维)常用接口的使用 &#x1f4a6;vector的常见构造&#xff08;初始化&#xff09; &#x1f4a6;vector…

ISIS配置以及详解

作者简介&#xff1a;大家好&#xff0c;我是Asshebaby&#xff0c;热爱网工&#xff0c;有网络方面不懂的可以加我一起探讨 :1125069544 个人主页&#xff1a;Asshebaby博客 当前专栏&#xff1a; 网络HCIP内容 特色专栏&#xff1a; 常见的项目配置 本文内容&am…

2024年天津中德应用技术大学专升本专业课报名及考试时间通知

天津中德应用技术大学2024年高职升本科专业课报名确认及考试通知 按照市高招办《2024年天津市高职升本科招生实施办法》&#xff08;津招办高发〔2023〕14号&#xff09;文件要求&#xff0c;天津中德应用技术大学制定了2024年高职升本科专业课考试报名、确认及考试实施方案&a…

JFrog----软件成分分析(SCA)简介

文章目录 1. SCA的重要性2. SCA的工作方式3. 安全漏洞分析4. 许可证合规性5. 代码质量和维护性结语 在当今的快速发展的软件行业中&#xff0c;软件成分分析&#xff08;Software Composition Analysis&#xff0c;简称SCA&#xff09;已成为一个不可或缺的工具。SCA的主要任务…

服务异步通讯

四、服务异步通讯 4.1初始MQ 4.1.1同步通讯和异步通讯 同步调用的优点: 时效性较强,可以立即得到结果 同步调用的问题: 耦合度高性能和吞吐能力下降有额外的资源消耗有级联失败问题异步通信的优点: 耦合度低吞吐量提升故障隔离流量削峰异步通信的缺点: 依赖于Broker的…

记一次SQL Server磁盘突然满了导致数据库锁死事件is full due to ‘LOG_BACKUP‘.

背景 最近我们的sql server 数据库磁盘在80左右&#xff0c;需要新增磁盘空间。还是处以目前可控的范围内&#xff0c;但是昨天晚上告警是80%&#xff0c;凌晨2:56分告警是90%&#xff0c;今天早上磁盘就满了。 经过 通过阿里云后台查看&#xff0c;磁盘已经占据99%&#xff0c…

蓝牙概述及基本架构介绍

蓝牙概述及基本架构介绍 1. 概述1.1 蓝牙的概念1.2 蓝牙的发展历程1.3 蓝牙技术概述1.3.1 Basic Rate(BR)1.3.2 Low Energy&#xff08;LE&#xff09; 2. 蓝牙的基本架构2.1 芯片架构2.2 协议架构2.2.1 官方协议中所展示的蓝牙协议架构2.2.1.1 全局分析2.2.1.2 局部分析 2.2.2…

广告公司选择企业邮箱的策略与技巧

对于广告公司而言&#xff0c;选择一款适合的企业邮箱不仅能提升工作效率&#xff0c;更能维护并强化公司的品牌形象。以下是在选择企业邮箱时需关注的关键因素和注意事项。 1、邮件服务商的安全性。 邮件服务商应具备严密的安全防护措施&#xff0c;包括反垃圾邮件、防病毒、防…

使用JDBC连接和操作数据库以及myBatis初级入门

JDBC简介和使用 java程序操作数据库的方式有很多种&#xff0c;下面列举一些市面上常用的方式&#xff1a; 从图片分析的知&#xff1a; MyBatis MyBatisPlus 这两个所占的比重比较大。都是用于简化JDBC开发的 JDBC&#xff1a;(Java DataBase Connectivity)&#xff0c;就…

95基于matlab的多目标优化算法NSGA3

基于matlab的多目标优化算法NSGA3&#xff0c;动态输出优化过程&#xff0c;得到最终的多目标优化结果。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 95matlab多目标优化 (xiaohongshu.com)

leetcode做题笔记1038. 从二叉搜索树到更大和树

给定一个二叉搜索树 root (BST)&#xff0c;请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 提醒一下&#xff0c; 二叉搜索树 满足下列约束条件&#xff1a; 节点的左子树仅包含键 小于 节点键的节点。节点的右子树仅包含键 大于 节点键的节点。左右…

智能优化算法应用:基于树种算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于树种算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于树种算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.树种算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

【腾讯云云上实验室】个人对腾讯云向量数据库的体验心得

目录 前言Tencent Cloud VectorDB概念使用初体验腾讯云向量数据库的优势应用场景有哪些&#xff1f;未来展望番外篇&#xff1a;腾讯云向量数据库的设计核心结语 前言 还是那句话&#xff0c;不用多说想必大家都能猜到&#xff0c;现在技术圈最火的是什么&#xff1f;非人工智…

【LeetCode热题100】【双指针】三数之和

给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元组。 示例 …