当前位置: 首页 > news >正文

Spring Boot简单多线程定时任务实现 | @Async | @Scheduled

Spring Boot简单多线程定时任务实现

实现步骤

1 创建一个Spring Boot项目

2 定义定时任务:

在这里插入图片描述

package com.jmd.timertasktest.task;import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;import java.time.LocalDateTime;/*** Created with IntelliJ IDEA.* User: Jiang* Time: 2023/12/24 024 21:53* File: TimerTaskUtil* Description:*/
@Configuration
@EnableScheduling  // 开启定时任务
@EnableAsync  // 开启多线程(异步)
public class TimerTaskTest {@Scheduled(cron = "0/5 * * * * ?")@Asyncpublic void testTimerTask1() throws InterruptedException {System.out.println("执行定时任务1 " + LocalDateTime.now());System.out.println("执行定时任务1的线程是-->" + Thread.currentThread().getName());Thread.sleep(10 * 1000);}@Scheduled(cron = "0/5 * * * * ?")@Asyncpublic void testTimerTask2() {System.out.println("执行定时任务2 " + LocalDateTime.now());System.out.println("执行定时任务2的线程是==>" + Thread.currentThread().getName());}}

在这里插入图片描述

执行定时任务1 2023-12-24T22:32:30.023176600
执行定时任务1的线程是-->task-1
执行定时任务2 2023-12-24T22:32:30.024173800
执行定时任务2的线程是==>task-2
执行定时任务2 2023-12-24T22:32:35.003081100
执行定时任务2的线程是==>task-3
执行定时任务1 2023-12-24T22:32:35.003081100
执行定时任务1的线程是-->task-4
执行定时任务1 2023-12-24T22:32:40.003165400
执行定时任务1的线程是-->task-5
执行定时任务2 2023-12-24T22:32:40.003165400
执行定时任务2的线程是==>task-6
执行定时任务2 2023-12-24T22:32:45.002857100
执行定时任务2的线程是==>task-7
执行定时任务1 2023-12-24T22:32:45.002857100
执行定时任务1的线程是-->task-8
执行定时任务1 2023-12-24T22:32:50.002249300
执行定时任务1的线程是-->task-2
执行定时任务2 2023-12-24T22:32:50.002966600

这种方式使用的是Spring默认的线程池SimpleAsyncTaskExecutor,Spring 使用 SimpleAsyncTaskExecutor 为每个任务生成一个新线程。(所以上面的运行结果可以发现sleep了10秒并不会影响定时任务的执行)

SimpleAsyncTaskExecutor 的缺点:默认的 SimpleAsyncTaskExecutor 为每个任务创建一个全新的线程,没有任何限制。在并发执行大量任务的情况下,这可能会导致系统资源耗尽。

解决方法(实现对线程创建和管理的细粒度控制):

  1. 可以在yml或properties中添加线程池配置

    spring:task:execution:pool:max-size: 10core-size: 8# keep-alive: 60queue-capacity: 100thread-name-prefix: Async-task
    

    在这里插入图片描述

  2. 使用ThreadPoolTaskExecutor

    package com.jmd.timertasktest.configuration;import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.AsyncConfigurer;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;/*** Created with IntelliJ IDEA.* User: Jiang* Time: 2023/12/24 024 23:43* File: TaskConfiguration* Description:*/
    @Configuration
    @EnableAsync
    public class TaskConfiguration implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5); // 核心线程数executor.setMaxPoolSize(10); // 最大线程数executor.setQueueCapacity(25); // 阻塞队列长度executor.setThreadNamePrefix("Async-");executor.initialize();return executor;}
    }
    

    在这里插入图片描述

@Async

Spring中的@Async注解是一种声明性方式,表示方法应该异步运行,即在单独的线程中运行,允许调用者继续执行而无需等待被调用方法的完成。

当使用 @Async 注解一个方法时,Spring 在背后执行以下操作:

  1. 它在启动时会给调用类创建一个代理
  2. 每当调用带有 @Async 注解的方法时,Spring 都会确保方法执行是由线程池中的线程执行的,从而允许调用方法毫不延迟地继续进行。

注意:

调用一个被@Async注解修饰的方法时,程序是不会等待方法执行的,直接执行下一个操作,缩短了响应时间,该方法通过线程池中的线程去执行了。

@Scheduled

@Scheduled注解是Spring Boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行。注意需要配合@EnableScheduling使用,@Scheduled主要有4种配置执行时间的方式:

  • cron
  • fixedRate
  • fixedDelay
  • initialDelay
  1. corn

    语法(年非必填):

    [] [] [小时] [] [] [] []
    

在这里插入图片描述

通配符说明:
  • * 表示所有值。 例如:在分的字段上设置 *,表示每一分钟都会触发。
  • ? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为”?” 具体设置为 0 0 0 10 * ?
  • - 表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。
  • , 表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
  • / 用于递增触发。如在秒上面设置”5/15” 表示从5秒开始,每增15秒触发(5,20,35,50)。 在日字段上设置’1/3’所示每月1号开始,每隔三天触发一次。
  • L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在周字段上设置”6L”这样的格式,则表示“本月最后一个星期五”
  • W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上置”15W”,表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,”W”前只能设置具体的数字,不允许区间”-“)。
  • # 序号(表示每月的第几个周几),例如在周字段上设置”6#3”表示在每月的第三个周六.注意如果指定”#5”,正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了) ;小提示:’L’和 ‘W’可以一组合使用。如果在日字段上设置”LW”,则表示在本月的最后一个工作日触发;周字段的设置,若使用英文字母是不区分大小写的,即MON与mon相同。
  1. fixedRate

    @Scheduled(fixedRate = 5000) //上一次开始执行时间点之后5秒再执行
    @Scheduled(fixedRateString = "5000")
    
  2. fixedDelay

    @Scheduled(fixedDelay = 5000) //上一次执行完毕时间点之后5秒再执行
    @Scheduled(fixedDelayString = "5000") //上一次执行完毕时间点之后5秒再执行
    
  3. initialDelay

    @Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
    @Scheduled(initialDelayString= "1000", fixedRate=5000)
    

线程池的执行:

在这里插入图片描述

http://www.lryc.cn/news/270134.html

相关文章:

  • sklearn学习的一个例子用pycharm jupyter
  • JVM的生命周期
  • ElasticSearch--基本操作
  • 大数据应用发展史:从搜索引擎时代到机器学习时代
  • java基础之String的不可变性
  • 【JS】Promise详解
  • 原生微信小程序如何动态配置主题颜色及如何调用子组件的方法
  • Java关键字(1)
  • 【机器学习合集】深度生成模型 ->(个人学习记录笔记)
  • Java将PDF转换为文本
  • Linux 运维工具之1Panel
  • 深入了解小红书笔记详情API:为内容创新提供动力
  • Animate 2024(Adobe an2024)
  • 尽量避免删改List
  • 【Linux操作系统】探秘Linux奥秘:用户、组、密码及权限管理的解密与实战
  • 计算机组成原理复习4
  • AutoSAR(基础入门篇)3.3-Autosar中RTE的数据一致性与Interface接口
  • 超维空间S2无人机使用说明书——52、初级版——使用PID算法进行基于yolo的目标跟踪
  • <JavaEE> TCP 的通信机制(一) -- 确认应答 和 超时重传
  • Spark任务调度与数据本地性
  • 【论文阅读】Self-Paced Curriculum Learning
  • C++简易线程池
  • 【MATLAB】PSO粒子群优化LSTM(PSO_LSTM)的时间序列预测
  • 产品经理学习-怎么写PRD文档
  • 第3课 获取并播放音频流
  • Spark编程实验四:Spark Streaming编程
  • Flink去重计数统计用户数
  • 力扣:62. 不同路径(动态规划,附python二维数组的定义)
  • 2022年全球运维大会(GOPS深圳站)-核心PPT资料下载
  • 8868体育助力意甲罗马俱乐部 迪巴拉有望付出