




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
复盘SpringBoot中定时任务和异步线程池项目中最近使用了多个定时任务处理业务需求,于是在实现业务逻辑过程中,产生了上图一些思考和疑问,现在利用空余时间进行一次复盘。项目搭建项目搭建环境:JDK1.8+SpringBoot主启动类:加上@EnableScheduling新建定时任务配置类:ScheduledTask;定义两个定时任务,简单打印一下线程名字和时间戳源码如下:@Component
public
class
ScheduledTask
{
@Scheduled(cron
=
"0/1
*
*
*
*
?")
public
void
scheduledTask1()
throws
InterruptedException
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask1
"
+
System.currentTimeMillis());
}
@Scheduled(cron
=
"0/1
*
*
*
*
?")
public
void
scheduledTask2()
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask2
"
+
System.currentTimeMillis());
}
}一、多任务串行执行1.相同定时任务先解决多任务定时相同时间,是否存在优先级执行顺序,执行上面的代码,打印日志如下图:从控制台日志发现,两个定时任务并没有存在一定的执行顺序,存在乱序现象。故:串行定时任务,没有明显的优先级关系。2.一个定时任务阻塞为了实现此场景的条件,将定时任务1中添加死循环逻辑。源码改动如下:
@Scheduled(cron
=
"0/1
*
*
*
*
?")
public
void
scheduledTask1()
throws
InterruptedException
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask1
"
+
System.currentTimeMillis());
while
(true)
{
Thread.sleep(5000);
}
}从控制台可以得出:多个定时任务时串行执行的,如果一个任务出现阻塞,其他的任务都会受到影响。二、多任务并行执行如果要实现并行执行,启动类需要在上面的基础上新增注解@EnableAsync。任务方法上新增@Async注解。源码如下:@Component
public
class
ScheduledTask
{
@Scheduled(cron
=
"0/1
*
*
*
*
?")
@Async
public
void
scheduledTask1()
throws
InterruptedException
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask1
"
+
System.currentTimeMillis());
}
@Scheduled(cron
=
"0/1
*
*
*
*
?")
@Async
public
void
scheduledTask2()
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask2
"
+
System.currentTimeMillis());
}
}执行结果如下图:从控制台中打印的线程名发现:每次执行任务时,都是创建新的线程执行,使用默认线程池SimpleAsyncTaskExecutor。默认情况下异步调用使用的线程池是SimpleAsyncTaskExecutor,该线程池是不被推荐,因为该线程池的线程不重用,每次调用都会创建一个新的线程。所以需要我们自定义线程池。自定义线程池1.自定义局部线程池局部线程池实际上就是指异步方法上需要指定使用该线程池,否则将使用默认线程池。搜索公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。配置异步线程池源码如下:@Component
public
class
AsyncTaskExecutorConfig
{
/**
*
重写AsyncTaskExecutor对象,实现全局异步线程,即@Async注解需指定线程池
*/
@Bean(value
=
"asyncTaskExecutor")
public
AsyncTaskExecutor
asyncTaskExecutor()
{
ThreadPoolTaskExecutor
executor
=
new
ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("defineAsyncTask-");
executor.setMaxPoolSize(10);
executor.setCorePoolSize(3);
executor.setQueueCapacity(100);
/*
线程池对拒绝任务的处理策略(rejectionpolicy):
当线程池已经达到最大线程数量,没有空闲线程时,新任务该如何处理
可选策略:
CallerRunsPolicy:当线程池没有能力处理时直接在执行方法的调用线程中运行被拒绝的任务
如果执行程序已经关闭,将丢弃该任务.
AbortPolicy:处理程序遭到拒绝时将抛出
RejectedExecutionException
*/
executor.setRejectedExecutionHandler(new
ThreadPoolExecutor.CallerRunsPolicy());
//等待所有任务调度完成在关闭线程池,保证所有的任务被正确处理
executor.setWaitForTasksToCompleteOnShutdown(true);
//线程池关闭时等待其他任务的时间,不能无限等待,确保应用最后能被关闭。而不是无限期阻塞
executor.setAwaitTerminationSeconds(60);
//线程池初始化
executor.initialize();
return
executor;
}
}定时任务源码修改如下:@Component
public
class
ScheduledTask
{
@Scheduled(cron
=
"0/1
*
*
*
*
?")
//指定自定义线程池
@Async("asyncTaskExecutor")
public
void
scheduledTask1()
throws
InterruptedException
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask1
"
+
System.currentTimeMillis());
}
@Scheduled(cron
=
"0/1
*
*
*
*
?")
@Async//未指定线程池,则使用默认线程池
public
void
scheduledTask2()
{
System.out.println(Thread.currentThread().getName()
+
"---scheduledTask2
"
+
System.currentTimeMillis());
}
}控制台执行结果如下:从图中依据线程名字,看到任务1均有自定义线程池defineAsyncTask-*执行,同时验证默认线程池SimpleAsyncTaskExecutor一直创建新线程执行。2.定义全局线程池上面需在@Async()注解中指定使用自定义线程池才有效,如果我们即不想指定线程池,又不想使用默认线程池池—全局线程池。定义全局线程池可以通过实现AsyncConfigurer或者继承AsyncConfigurerSupport。源码如下:@Configuration
public
class
AsyncGlobalConfig
extends
AsyncConfigurerSupport
{
private
static
final
String
THREAD_PREFIX
=
"defineGlobalAsync-";
@Override
public
Executor
getAsyncExecutor()
{
ThreadPoolTaskExecutor
executor
=
new
ThreadPoolTaskExecutor();
executor.setThreadNamePrefix(THREAD_PREFIX);
executor.setCorePoolSize(3);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(60);
executor.setRejectedExecutionHandler(new
ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return
executor;
}
}再次执行上面的任务,结果如下:任务1,指定自定义线程池,则有该线程池执行任务,其余未指定线程池,则使用自定义的全局线程池执行任务。三、异常处理使用过线程池执行任务的伙伴应该会知道,线程提交任务分为execute()方式和submit()方式。对于异步submit提交任务时,使用Future.get()方法获取返回结果时,主线程阻塞并可以处理线程池中的异常。对于execute()方式提交任务,当异步任务返回类型为void,异常不会传播到调用线程,故需要通过实现AsyncUncaughtExceptionHandler接口创建自定义异常处理。故在上面配置全局线程池的基础上,处理异常。从源码中可以得出AsyncConfigurerSupport提供了两个方法,其中getAsyncExecutor()是定义线程池的,getAsyncUncaughtExceptionHandler()是用于处理异常的。处理异常源码实现如下:自定义异常处理实现类:static
class
CustomAsyncExceptionHandler
implements
AsyncUncaughtExceptionHandler
{
@Override
public
void
handleUncaughtExce
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- SAP计划策略总结模版
- 出生婴幼儿的日常护理
- 阳泉职业技术学院《道教文化与养生智慧》2023-2024学年第一学期期末试卷
- 陕西工业职业技术学院《地图学与遥感》2023-2024学年第二学期期末试卷
- 陕西师范大学《环境医学》2023-2024学年第一学期期末试卷
- 陕西服装工程学院《泰语发音和对话实践(一)》2023-2024学年第二学期期末试卷
- 陕西省咸阳市陕科大重点达标名校2025届初三下学期中考模拟卷(一)物理试题试卷含解析
- 陕西省延安市吴起县2025年高三生物试题质量检测试题(二)生物试题试卷含解析
- 八五普法教育课件
- 陕西省西安市2025届高三下学期阶段性测试(四)数学试题含解析
- 3.1《中国科学技术史序言(节选)》教学设计-【中职专用】高二语文同步讲堂(高教版2024拓展模块上册)
- 连乐铁路指导性施工组织设计
- 2025年河南郑州航空港经济综合实验区招考高频重点模拟试卷提升(共500题附带答案详解)
- 2025年电力电缆安装运维工(高级)职业技能鉴定备考试题库资料(含答案)
- 《外科学》教学课件:创伤课件new
- 护理人员中医技术使用手册(2024版)
- 沪教版(五四学制)(2024)六年级下册单词表+默写单
- 【八下英语译林版】八下英语 Unit 4 单元知识点详解
- (2025)时事政治题库(含参考答案)
- 2025年河北邢台市市直事业单位招聘212名高层次人才历年高频重点提升(共500题)附带答案详解
- 2015-2024年高考物理试题分类汇编:热学和光学实验(全国解析版)
评论
0/150
提交评论