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 的背景. ...
随机推荐
- linux内核开源代码地址下载
https://www.kernel.org/pub/linux/kernel/v2.6/
- PAT B1041 考试座位号(15)
解题要点: 使用结构体保存准考证号,考试座位号 试机座位号作考生数组下标 通过试机座位号获取考生号,座位号 考生号使用long long存放 //课本AC代码 #include <cstdio& ...
- 【问题】【编程环境】fatal error: security/pam_appl.h
[问题] 今天在docker中基于centos镜像的容器编译gogs遇到错误 似乎缺少库文件 [解决] yum -y install pam-devel
- mysql-tpcc测试
os: centos 7.4 db: mysql 5.7 software: tpcc-mysql TPC-C是专门针对联机交易处理系统(OLTP系统)的规范. tpcc-mysql是percona基 ...
- Rust 优劣势: v.s. C++ / v.s. Go(持续更新)
Rust 发展速度比 C++ 强很多.如果去翻 open-std 的故纸堆,会发现 C++ 这边有很多人(包括标准委员会的人)提了有用的提案,但后来大多不了了之或经历了非常长的时间才进入标准. > ...
- C#中判断文件夹或文件是否存在的方法
一.根据虚拟路径获取文件物理路径: string savePath = Server.MapPath("~/Uploads/RemoteDatum/"); 二.判断文件夹是否存在 ...
- nfs服务器的搭建和使用
目录 更新记录 1.nfs介绍 1.1 nfs概念 1.2 nfs工作原理 1.3 nfs通讯过程 2.搭建和测试 NFS 服务器 2.1 搭建NFS服务器 2.2 测试NFS服务器 3.在线调试:N ...
- MySQL的左连接查询,只取出最大的一条数据
今天有个需求,是通过两张表进行查询.一对多的关系.通过一个主键,取出其中的一条.开始以为还好,直接用用了left join on进行查询.却发现了问题所在.其他的好弄.开始的写法借鉴这篇博客:http ...
- fastadmin 金额 字段类型及html验证
金额 字段类型 整数 小数 decimal 10 2 float 10 2 html验证 <div class="form-group&q ...
- 性能测试分析工具nmon文件分析时报错解决办法
1.使用nmon analyzer V334.xml分析数据时,如果文件过大,可以修改Analyser页签中的INTERVALS的最大值: 2.查找生成的nmon文件中包含的nan,删掉这些数据(需要 ...