ThreadPoolTaskExecutor使用详解(转)
当并发或者异步操作,都会用到ThreadPoolTaskExecutor。现在对线程池稍作理解。
/***
*@Auth dzb
*@Date 22:29 2018/8/29
*@Description: 线程池
*@Version 1.0
*/
@Configuration
public class AsynTaskExecutePool implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);//核心池大小
executor.setMaxPoolSize(100);//最大线程数
executor.setQueueCapacity(1000);//队列程度
executor.setKeepAliveSeconds(1000);//线程空闲时间
executor.setThreadNamePrefix("tsak-asyn");//线程前缀名称
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//配置拒绝策略
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... Object) {
System.err.println("error=================="+throwable.getMessage());
System.err.println("Method=================="+method.getName());
System.err.println("Object=================="+Object);
}
};
}
}
rejectedExecutionHandler字段用于配置拒绝策略,常用的拒绝策略如下:
AbortPolicy,用于被拒绝任务的处理程序,它将抛出RejectedExecutionException。
CallerRunsPolicy,用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务。
DiscardOldestPolicy,用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试execute。
DiscardPolicy,用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。
其他说明:
如果有特殊的业务需求,用户可以选择使用自定义策略,只需实现RejectedExecutionHandler接口即可。
配置threadNamePrefix属性,出问题可以随时排查。
提交任务:
void execute(Runnable command)
如果实现使用异步执行策略,则调用可能立即返回,或者在同步执行的情况下可能会阻塞。
public java.util.concurrent.Future <?> submit(java.lang.Runnable task)
提交Runnable任务以执行,接收表示该任务的Future。未来将null在完成后返回结果。
处理流程
当一个任务被提交到线程池时,首先查看线程池的核心线程是否都在执行任务,否就选择一条线程执行任务,是就执行第二步。
查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第三步。
查看任务队列是否已满,不满就将任务存储在任务队列中,否则执行第四步。
查看线程池是否已满,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。
在ThreadPoolExecutor中表现为:
如果当前运行的线程数小于corePoolSize,那么就创建线程来执行任务(执行时需要获取全局锁)。
如果运行的线程大于或等于corePoolSize,那么就把task加入BlockQueue。
如果创建的线程数量大于BlockQueue的最大容量,那么创建新线程来执行该任务。
如果创建线程导致当前运行的线程数超过maximumPoolSize,就根据饱和策略来拒绝该任务。
关闭线程池
showdow()实现的代码:
if (this.executor != null) {
if (this.waitForTasksToCompleteOnShutdown) {
this.executor.shutdown();//中断未执行完的线程
} else {
Iterator var1 = this.executor.shutdownNow().iterator();
while(var1.hasNext()) {
Runnable remainingTask = (Runnable)var1.next();
this.cancelRemainingTask(remainingTask);//取消所有剩下需要执行的线程
}
}
调用shutdown或者shutdownNow,两者都不会接受新的任务,而且通过调用要停止线程的interrupt方法来中断线程,有可能线程永远不会被中断,不同之处在于shutdownNow会首先将线程池的状态设置为STOP,然后尝试停止所有线程(有可能导致部分任务没有执行完)然后返回未执行任务的列表。而shutdown则只是将线程池的状态设置为shutdown,然后中断所有没有执行任务的线程,并将剩余的任务执行完。
配置线程个数
如果是CPU密集型任务,那么线程池的线程个数应该尽量少一些,一般为CPU的个数+1条线程。
如果是IO密集型任务,那么线程池的线程可以放的很大,如2*CPU的个数。
对于混合型任务,如果可以拆分的话,通过拆分成CPU密集型和IO密集型两种来提高执行效率;如果不能拆分的的话就可以根据实际情况来调整线程池中线程的个数。
监控线程池状态
常用状态:
taskCount:线程需要执行的任务个数。
completedTaskCount:线程池在运行过程中已完成的任务数。
largestPoolSize:线程池曾经创建过的最大线程数量。
getPoolSize获取当前线程池的线程数量。
getActiveCount:获取活动的线程的数量
通过继承线程池,重写beforeExecute,afterExecute和terminated方法来在线程执行任务前,线程执行任务结束,和线程终结前获取线程的运行情况,根据具体情况调整线程池的线程数量。
rejectedExecutionHandler字段用于配置拒绝策略,常用的拒绝策略如下:
AbortPolicy,用于被拒绝任务的处理程序,它将抛出RejectedExecutionException。
CallerRunsPolicy,用于被拒绝任务的处理程序,它直接在execute方法的调用线程中运行被拒绝的任务。
DiscardOldestPolicy,用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试execute。
DiscardPolicy,用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。
其他说明:
为了实现某些特殊的业务需求,用户可以选择使用自定义策略,只需实现RejectedExecutionHandler接口即可。
建议配置threadNamePrefix属性,出问题时可以更方便的进行排查。
提交任务
无返回值的任务使用execute(Runnable)
有返回值的任务使用submit(Runnable)
处理流程
当一个任务被提交到线程池时,首先查看线程池的核心线程是否都在执行任务,否就选择一条线程执行任务,是就执行第二步。
查看核心线程池是否已满,不满就创建一条线程执行任务,否则执行第三步。
查看任务队列是否已满,不满就将任务存储在任务队列中,否则执行第四步。
查看线程池是否已满,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务。
在ThreadPoolExecutor中表现为:
如果当前运行的线程数小于corePoolSize,那么就创建线程来执行任务(执行时需要获取全局锁)。
如果运行的线程大于或等于corePoolSize,那么就把task加入BlockQueue。
如果创建的线程数量大于BlockQueue的最大容量,那么创建新线程来执行该任务。
如果创建线程导致当前运行的线程数超过maximumPoolSize,就根据饱和策略来拒绝该任务。
关闭线程池
调用shutdown或者shutdownNow,两者都不会接受新的任务,而且通过调用要停止线程的interrupt方法来中断线程,有可能线程永远不会被中断,不同之处在于shutdownNow会首先将线程池的状态设置为STOP,然后尝试停止所有线程(有可能导致部分任务没有执行完)然后返回未执行任务的列表。而shutdown则只是将线程池的状态设置为shutdown,然后中断所有没有执行任务的线程,并将剩余的任务执行完。
配置线程个数
如果是CPU密集型任务,那么线程池的线程个数应该尽量少一些,一般为CPU的个数+1条线程。
如果是IO密集型任务,那么线程池的线程可以放的很大,如2*CPU的个数。
对于混合型任务,如果可以拆分的话,通过拆分成CPU密集型和IO密集型两种来提高执行效率;如果不能拆分的的话就可以根据实际情况来调整线程池中线程的个数。
监控线程池状态
常用状态:
taskCount:线程需要执行的任务个数。
completedTaskCount:线程池在运行过程中已完成的任务数。
largestPoolSize:线程池曾经创建过的最大线程数量。
getPoolSize获取当前线程池的线程数量。
getActiveCount:获取活动的线程的数量
通过继承线程池,重写beforeExecute,afterExecute和terminated方法来在线程执行任务前,线程执行任务结束,和线程终结前获取线程的运行情况,根据具体情况调整线程池的线程数量。
参考来源:
[1] https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/concurrent/ThreadPoolTaskExecutor.html
参考链接:https://blog.csdn.net/foreverling/article/details/78073105
参考链接:https://blog.csdn.net/sdmxdzb/article/details/82193847
ThreadPoolTaskExecutor使用详解(转)的更多相关文章
- ThreadPoolTaskExecutor使用详解
当我们需要实现并发.异步等操作时,通常都会使用到ThreadPoolTaskExecutor,现对其使用稍作总结. 配置ThreadPoolTaskExecutor通常通过XML方式配置,或者通过Ex ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
- Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android XML shape 标签使用详解 一个android开发者肯定懂得使用 xml 定义一个 Drawable,比如定义一个 rect 或者 circle 作为一个 View 的背景. ...
随机推荐
- Shell脚本中计算字符串长度的5种方法
有时在Linux操作系统中需要计算某个字符串的长度,通过查询资料整理了下目前Shell中获取字符串的长度的多种方法,在这里分享给大家,方法如下: 方法1: 使用wc -L命令wc -L可以获取到当前行 ...
- 用三台虚拟机搭建Hadoop全分布集群
用三台虚拟机搭建Hadoop全分布集群 所有的软件都装在/home/software下 虚拟机系统:centos6.5 jdk版本:1.8.0_181 zookeeper版本:3.4.7 hadoop ...
- Linux系列之ftp
ftp的详细用法,请访问https://www.cnblogs.com/juandx/p/3998418.html 1.Windows搭建IIS类型的ftp服务器 步骤 1.打开控制面板,接着打开程序 ...
- find_in_set使用
FIND_IN_SET(str,strList) str 要查询的字符串 strList 字段名,参数以“,”分隔,如(1,2,6,8) 查询字段(strList)中包含的结果,返回结果null或记录 ...
- nginx-consul-template
概述Consul-template 是 HashiCorp 基于 Consul 所提供的可扩展的工具,通过监听 Consul中的数据变化,动态地修改一些配置文件中地模板.常用于在 Nginx.HAPr ...
- 思科设备ACL与NAT技术
ACL 访问控制列表(Access Control Lists),是应用在路由器(或三层交换机)接口上的指令列表,用来告诉路由器哪些数据可以接收,哪些数据是需要被拒绝的,ACL的定义是基于协议的,它适 ...
- Win32汇编-编写PE结构解析工具
汇编语言(assembly language)是一种用于电子计算机.微处理器.微控制器或其他可编程器件的低级语言,亦称为符号语言.在汇编语言中,用助记符(Mnemonics)代替机器指令的操作码,用地 ...
- GNU g++常用编译选项用法
GNU g++常用编译选项用法 本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/30686/showart_1210761.html GCC ...
- A Pythonic Card Deck: __len__ & __getitem__ & for 循环的嵌套
1. 列表生成式的嵌套 for 循环: 示例如下: li1 = range(1,6) li2 = list("ABC") # list("ABC") 的结果为 ...
- vue进阶:基于vue-cli创建项目(搭建手脚架)
vue-cli安装.创建项目 基于vue-cli创建的项目进行开发 使用vue-cli图形化界面搭建项目 插件与工具 一.vue-cli简介.安装.创建项目 Vue-cli是基于Vue.js进行快速开 ...