环境:SpringBoot3.2.5
1. 简介
Spring提供了强大的支持来处理异步任务和定时任务。@Async注解用于方法上,使其在独立线程中异步执行,返回值通过Future或CompletableFuture返回给调用者。而@Scheduled则用于定义定时任务,如定期执行某个方法。可以通过配置来控制线程池的大小和任务的调度策略,使得应用能够更加高效地利用资源,提高响应速度和用户体验。这两种机制是Spring框架中用来增强应用程序灵活性和性能的重要工具。
如下示例,基于SpringBoot环境下如何开启及应用异步任务及定时任务
异步任务调用
// 1.开启异步功能支持@EnableAsyncpublic class AppConfig {}// 2.使用@Async标注方法异步线程调用@Servicepublic class EmailService {@Asyncpublic void sendMail() {// TODO}}
通过上面简单的2步即可实现方法的在非调用者线程中执行。
定时任务
// 1.开启定时任务功能支持public class AppConfig {}// 2.使用@Scheduled标注方法异步线程调用public class StatisticsService {// 每天凌晨12点执行(cron = "0 0 * * ?")public void calcDayAmount) {// TODO}}
通用定时任务也非常的简单只需要两步;上面使用了cron表达式,你还可以通过@Scheduled注解配置其它的属性,比如:固定周期执行等等。
以上是关于异步任务和定时任务的基本使用;在介绍新特性之前你必须要知道关于Spring对异步、调度任务提供了抽象分别是TaskExecutor和TaskScheduler接口。
1.1 异步任务TaskExecutor
关于异步任务Spring内置了非常多的内置实现,你几乎不需要自己去实现。
SyncTaskExecutor:主要应用于测试,同步执行也就是在调用者线程中执行。
SimpleAsyncTaskExecutor:每次调用启动一个新线程,不过它支持并发执行,你可以设置并发数。
ConcurrentTaskExecutor:一般很少直接使用。
ThreadPoolTaskExecutor:最为常用,它公开了JUC中ThreadPoolExecutor的属性,你可以通过bean属性方式进行配置。
在实际的项目中你可以定义上面的类型的bean来满足自己的线程池需求,如下示例:
SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor() ;executor.setThreadNamePrefix("async-pack-") ;return executor ;}
异步任务的执行将会通过上面配置的线程池。
1.2 定时任务TaskScheduler
该接口中定义了各种定时任务的执行方式,详细你可以查看具体的API说明。
通过TaskScheduler,Spring允许开发者在不关心底层线程管理(特别是当部署在需要特定线程管理策略的环境中时)的情况下,灵活地安排任务的执行。
通常,我们可以在容器中通过自定义ThreadPoolTaskScheduler或ScheduledExecutorService来实现自定义配置,如下示例:
ThreadPoolTaskScheduler threadPoolTaskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() ;scheduler.setPoolSize(2) ;scheduler.setThreadNamePrefix("scheduler-pack-") ;return scheduler ;}
在这里你可以根据自己的需要自定义相关线程池的配置信息。
上面我们通过简短的篇幅介绍了在Spring中异步任务&定时任务的应用使用方式。接下来,我将介绍从Spring6.1开始新增的新特性。
2. 新特性
在之前有一篇文章中,我介绍了如何暂停&恢复定时任务,大家可以查看下面这篇文章
在这篇文章中我们通过自定义的方式去停止和重启定时任务,虽然达到了目的,但是还是不够优雅,并且只是针对定时任务的停止和重启,那异步任务又该如何处理呢?
2.1 异步任务
从 6.1 开始,ThreadPoolTaskExecutor 通过 Spring 的生命周期管理提供了暂停/恢复功能和优雅关机功能。
2.2 定时任务
从 6.1 开始,ThreadPoolTaskScheduler 通过 Spring 的生命周期管理提供了暂停/恢复功能和优雅关闭功能。
2.3 异步任务虚拟线程支持
从 6.1 开始,SimpleAsyncTaskExecutor 还新增了 "virtualThreads"(虚拟线程)选项,该选项与 JDK 21 的虚拟线程一致,同时 SimpleAsyncTaskExecutor 还具备优雅关闭功能。
2.4 定时任务虚拟线程支持
从 6.1 开始,还有一个名为 SimpleAsyncTaskScheduler 的新选项,它与 JDK 21 的虚拟线程(Virtual Threads)一致,使用单个调度线程,但每次执行计划任务时都会启动一个新线程(固定延迟任务除外,它们都在单个调度线程上运行,因此建议使用固定速率和 cron 触发器)。
接下来,我将详细介绍异步任务&定时任务暂停、恢复、优雅停机功能进行详细介绍。
3. 实战案例
3.1 异步任务
配置异步任务线程池
@Beanpublic ThreadPoolTaskExecutor threadPoolTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() ;executor.setCorePoolSize(5) ;executor.setMaxPoolSize(5) ;executor.setQueueCapacity(20) ;return executor ;}
定义异步任务
private ThreadPoolTaskExecutor threadPoolTaskExecutor ;public void async1() {System.err.printf("%s, 异步任务async1执行...%n", Thread.currentThread().getName()) ;}// 停止异步任务public void stop() {this.threadPoolTaskExecutor.stop(() -> {System.err.println("异步任务成功停止...") ;}) ;}// 恢复异步任务public void start() {this.threadPoolTaskExecutor.start() ;}
上面stop和start方法是Spring6.1新增的新功能,用来停止和暂停异步任务。
定义接口
public String async1() {this.asyncService.async1() ;return "executor async task success" ;}public String stop() {this.asyncService.stop() ;return "stop success" ;}public String start() {this.asyncService.start() ;return "start success" ;}
接下来,进行测试
多次访问如下接口

控制台输出如下

正常执行异步任务,接下来访问/stop接口


方法执行成功,接下来我们再次访问上面的异步任务接口

控制台没有任何的输出,异步任务并没有执行。注意:我请求了5次
接下来,方法/start接口来恢复异步任务

注意:当成功访问该接口后,你会发现上次访问的5次异步任务执行了

这说明了,异步任务当时是没有执行,不过当恢复会任务会立马执行,因为内部是通过JUC中的Lock锁实现的。
注意:如果你的异步任务是个耗时任务,那么正在执行的异步任务是不会暂停的,只是新任务不会执行。
3.2 定时任务
其实,定时任务的暂停与恢复与异步任务差不多,至少方法都是相同的。
配置定时任务
ThreadPoolTaskScheduler threadPoolTaskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() ;scheduler.setPoolSize(5) ;scheduler.setThreadNamePrefix("scheduler-pack-") ;return scheduler ;}
定时任务
private ThreadPoolTaskScheduler threadPoolTaskScheduler ;(fixedRate = 3000)public void scheduler() {System.err.printf("%s, 定时任务开始执行...%n", Thread.currentThread().getName()) ;}public void stop() {this.threadPoolTaskScheduler.stop(() -> {System.err.println("定时任务成功停止...") ;}) ;}public void start() {this.threadPoolTaskScheduler.start() ;}
调用接口这里就不写了,当定时任务执行时,调用了stop会,定时任务将会暂停执行。
注意:定时任务从暂停到恢复后,这暂停期间应该执行的定时任务会一次性全部执行哦。
3.3 优雅关闭
关于优雅关闭,不管是异步任务还是定时任务,都对应的提供了下面这个方法
ThreadPoolTaskExecutor#initiateShutdown() ;ThreadPoolTaskScheduler#initiateShutdown() ;
通过调用上面方法即可完成优雅的关闭。其内部调用的线程池对象的shutdown方法。
以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏
推荐文章
REST API中的Patch请求大家都用错了,这才是正确姿势
全新升级:SpringBoot Admin可视化监控工具全面解析
解锁Spring资源Resource的强大功能,提升开发效率
SpringBoot整合Flink CDC,实时追踪数据变动,无缝同步至Redis
【高效开发】使用Spring Data JPA的QBE功能,轻松构建查询条件
你以为只有Controller一种接口定义方式?详解Web函数式接口



