大数跨境
0
0

Spring6.1 异步和定时任务新特性,太实用了

Spring6.1 异步和定时任务新特性,太实用了 Spring全家桶实战案例
2024-09-10
0
导读:Spring6.1 异步和定时任务新特性,太实用了

环境:SpringBoot3.2.5



1. 简介

Spring提供了强大的支持来处理异步任务和定时任务。@Async注解用于方法上,使其在独立线程中异步执行,返回值通过FutureCompletableFuture返回给调用者。而@Scheduled则用于定义定时任务,如定期执行某个方法。可以通过配置来控制线程池的大小和任务的调度策略,使得应用能够更加高效地利用资源,提高响应速度和用户体验。这两种机制是Spring框架中用来增强应用程序灵活性和性能的重要工具

如下示例,基于SpringBoot环境下如何开启及应用异步任务及定时任务

异步任务调用

// 1.开启异步功能支持@EnableAsyncpublic class AppConfig {}// 2.使用@Async标注方法异步线程调用@Servicepublic class EmailService {  @Async  public void sendMail() {    // TODO  }

通过上面简单的2步即可实现方法的在非调用者线程中执行。

定时任务

// 1.开启定时任务功能支持@EnableSchedulingpublic class AppConfig {}// 2.使用@Scheduled标注方法异步线程调用@Componentpublic class StatisticsService {  // 每天凌晨12点执行  @Scheduled(cron = "0 0 * * ?")  public void calcDayAmount) {    // TODO  }}

通用定时任务也非常的简单只需要两步;上面使用了cron表达式,你还可以通过@Scheduled注解配置其它的属性,比如:固定周期执行等等。

以上是关于异步任务和定时任务的基本使用;在介绍新特性之前你必须要知道关于Spring对异步、调度任务提供了抽象分别是TaskExecutorTaskScheduler接口。

1.1 异步任务TaskExecutor

关于异步任务Spring内置了非常多的内置实现,你几乎不需要自己去实现。

  • SyncTaskExecutor:主要应用于测试,同步执行也就是在调用者线程中执行。

  • SimpleAsyncTaskExecutor:每次调用启动一个新线程,不过它支持并发执行,你可以设置并发数。

  • ConcurrentTaskExecutor:一般很少直接使用。

  • ThreadPoolTaskExecutor:最为常用,它公开了JUC中ThreadPoolExecutor的属性,你可以通过bean属性方式进行配置。

     

在实际的项目中你可以定义上面的类型的bean来满足自己的线程池需求,如下示例:

@BeanSimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {  SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor() ;  executor.setThreadNamePrefix("async-pack-") ;  return executor ;}

异步任务的执行将会通过上面配置的线程池。

1.2 定时任务TaskScheduler

该接口中定义了各种定时任务的执行方式,详细你可以查看具体的API说明。

通过TaskScheduler,Spring允许开发者在不关心底层线程管理(特别是当部署在需要特定线程管理策略的环境中时)的情况下,灵活地安排任务的执行。

通常,我们可以在容器中通过自定义ThreadPoolTaskScheduler或ScheduledExecutorService来实现自定义配置,如下示例:

@BeanThreadPoolTaskScheduler threadPoolTaskScheduler() {  ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() ;  scheduler.setPoolSize(2) ;  scheduler.setThreadNamePrefix("scheduler-pack-") ;  return scheduler ;}

在这里你可以根据自己的需要自定义相关线程池的配置信息。

上面我们通过简短的篇幅介绍了在Spring中异步任务&定时任务的应用使用方式。接下来,我将介绍从Spring6.1开始新增的新特性。

2. 新特性

在之前有一篇文章中,我介绍了如何暂停&恢复定时任务,大家可以查看下面这篇文章

SpringBoot3优雅停止/重启定时任务

在这篇文章中我们通过自定义的方式去停止和重启定时任务,虽然达到了目的,但是还是不够优雅,并且只是针对定时任务的停止和重启,那异步任务又该如何处理呢?

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 ;}

定义异步任务

@Resourceprivate ThreadPoolTaskExecutor threadPoolTaskExecutor ;@Asyncpublic 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新增的新功能,用来停止和暂停异步任务。

定义接口

@GetMapping("/1")public String async1() {  this.asyncService.async1() ;  return "executor async task success" ;}@GetMapping("/stop")public String stop() {  this.asyncService.stop() ;  return "stop success" ;}@GetMapping("/start")public String start() {  this.asyncService.start() ;  return "start success" ;}

接下来,进行测试

多次访问如下接口

控制台输出如下

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

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

控制台没有任何的输出,异步任务并没有执行。注意:我请求了5次

接下来,方法/start接口来恢复异步任务

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

这说明了,异步任务当时是没有执行,不过当恢复会任务会立马执行,因为内部是通过JUC中的Lock锁实现的。

注意:如果你的异步任务是个耗时任务,那么正在执行的异步任务是不会暂停的,只是新任务不会执行。

3.2 定时任务

其实,定时任务的暂停与恢复与异步任务差不多,至少方法都是相同的。

配置定时任务

@BeanThreadPoolTaskScheduler threadPoolTaskScheduler() {  ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() ;  scheduler.setPoolSize(5) ;  scheduler.setThreadNamePrefix("scheduler-pack-") ;  return scheduler ;}

定时任务

@Resourceprivate ThreadPoolTaskScheduler threadPoolTaskScheduler ;
@Scheduled(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详细记录SQL执行耗时情况

SpringBoot一个非常强大的数据绑定类

不知道这些不要说玩转了Controller接口

一文让你彻底搞定Spring Security的基本使用

请一定牢记SpringBoot项目开发中的8个扩展接口

全新升级:SpringBoot Admin可视化监控工具全面解析

解锁Spring资源Resource的强大功能,提升开发效率

SpringBoot整合Flink CDC,实时追踪数据变动,无缝同步至Redis

【高效开发】使用Spring Data JPA的QBE功能,轻松构建查询条件

你以为只有Controller一种接口定义方式?详解Web函数式接口

使用Vault保护SpringBoot配置文件中的敏感数据

这些强大的工具类助你提升开发效率

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832