Spring Task 定时任务没有定时执行是为什么?

embedded/2024/9/24 12:21:32/

目录

      • SpringBoot 定时任务的原理
      • 任务一直阻塞会怎么样?
      • 多个定时任务的执行
      • 具有相同表达式的定时任务,它们的执行顺序如何?
      • Spring Task 和 Linux crontab 的 cron 语法区别?
      • 在 cron 语法中容易犯的错误
      • @Async 异步注解原理及作用
      • 并发执行任务如何配置?
      • 其他问题
      • 总结

在日常开发中,定时任务的应用已经变得十分常见,例如定时发送邮件、短信,数据定时转储等。然而,有时候我们会遇到定时任务没有按照预期执行的情况。本文将讨论 Spring Task 中定时任务执行的原理以及可能遇到的相关问题。

SpringBoot 定时任务的原理

绝大部分开发者在使用 Spring Boot 时都会使用它提供的定时任务 Starter 和定时任务的注解。因此,让我们首先了解一下 Spring Boot 实现定时任务的原理以及相关注解的作用。

自 Spring 3.0 版本以后,Spring 使用 @Scheduled 注解来支持定时任务。

在使用时,我们需要在应用的启动类上加上 @EnableScheduling 注解,该注解从 Spring 3.1 开始提供。

然而,在 Spring 3.0 版本之前,我们通常会通过 XML 配置和 @Scheduled 注解配合使用来实现定时任务。而 @EnableScheduling 注解实际上相当于该 XML 配置的简化版。它的作用是发现标记了 @Scheduled 注解的方法,没有该注解的方法将不会被执行。但是在大多数情况下,我们只需要关注目标实现,而不必深究其背后的细节。

任务一直阻塞会怎么样?

为了更好地理解定时任务的执行过程,我们进行了一个简单的实验:编写一个每隔 20 秒执行一次的定时任务,并在其中加入一个断点。

实验结果显示,当遇到断点时,后续的任务会被阻塞。这是因为线程池中只有一个线程用于执行任务,而该线程被阻塞后,后续任务将无法执行。线程池内部采用 DelayQueue 延迟队列实现,其特点是无界、延迟、阻塞,能够按照一定的顺序执行工作队列中的元素。

多个定时任务的执行

根据前面的实验结果,我们知道默认情况下,任务的线程池只有一个线程,因此多个定时任务应该是串行执行的。如果一个任务被阻塞,其他任务也会受到影响。

那么,如果我们将线程池的线程数设置为多个,会发生什么呢?实验结果显示,即使线程池中包含多个线程,多个定时任务仍然是串行执行的。只有在使用自定义的线程池,并且在任务上加上 @Async 注解时,才能实现并发执行。

具有相同表达式的定时任务,它们的执行顺序如何?

具有相同表达式的定时任务的执行顺序与调度有关。默认情况下,它们是串行执行的,首先获取到 CPU 时间片的任务会先执行。在多线程的情况下,具体的执行顺序取决于线程池的线程数、所用队列等因素。

Spring Task 和 Linux crontab 的 cron 语法区别?

两者的 cron 表达式非常相似,但需要注意的是,Linux 的 crontab 只提供了分钟级别的最小粒度,而 Spring Task 的最小粒度从秒开始。

在 cron 语法中容易犯的错误

在编写 cron 表达式时,很容易犯一些错误。例如,要求编写每十分钟执行一次的 cron 语句时,可能会写成类似以下的版本:

0 0/10 * * * ?

因此,在编写 cron 表达式后,建议适当降低执行间隔时间进行测试,或者使用在线工具检测 cron 脚本是否正确。

@Async 异步注解原理及作用

Spring Task 中与异步相关的注解有两个,一个是 @EnableAsync,另一个是 @Async

默认情况下,@Async 注解会使方法仍然由一个线程同步执行。要想实现异步执行,需要在启动类上加上 @EnableAsync 注解,并定义一个线程池。

并发执行任务如何配置?

我们可以通过两种方式来配置并发执行任务:

  1. 将默认的线程池替换为自定义的线程池。
  2. 不改变任务调度器默认使用的线程池,而是将任务交给一个异步线程池去执行。

通过这些方式,我们可以让任务高效地并发执行,提高系统的性能。

java">方式一,我们可以将默认的线程池替换为我们自定义的线程池。通过ScheduleConfig配置文件实现SchedulingConfigurer接口,并重写setSchedulerfang方法。可实现AsyncConfigurer接口复写getAsyncExecutor获取异步执行器,getAsyncUncaughtExceptionHandler获取异步未捕获异常处理器@Configurationpublic
class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));}
}
方式二:不改变任务调度器默认使用的线程池,而是把当前任务交给一个异步线程池去执行。@Scheduled(fixedRate = 1000*10,initialDelay = 1000*20)@Async("hyqThreadPoolTaskExecutor")public void test(){System.out.println(Thread.currentThread().getName()+"--->xxxxx--->"+Thread.currentThread().getId());}//自定义线程池@Bean(name = "hyqThreadPoolTaskExecutor")public TaskExecutor  getMyThreadPoolTaskExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(20);taskExecutor.setMaxPoolSize(200);taskExecutor.setQueueCapacity(25);taskExecutor.setKeepAliveSeconds(200);taskExecutor.setThreadNamePrefix("hyq-threadPool-");taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.setWaitForTasksToCompleteOnShutdown(true);taskExecutor.setAwaitTerminationSeconds(60);taskExecutor.initialize();return taskExecutor;

其他问题

  • 如果定时任务没有生效,需要检查是否加上了 @EnableScheduling 注解。
  • 如果异步任务没有生效,需要检查是否加上了 @EnableAsync 注解,并且定义了线程池,否则仍然是串行执行的。

总结

本文介绍了 Spring Boot 定时任务的原理,通过实验探究了延迟队列及串行、并行、并发的概念。对比了 Linux 下的 crontab 和 Spring 的 cron 表达式区别以及常见的错误。最后通过实验异步注解,两种方式配置线程池,使任务能够高效运行。希望本文能够对你有所帮助。


http://www.ppmy.cn/embedded/37011.html

相关文章

JavaScript异步编程——03-Ajax传输json和XML

Ajax 传输 JSON JSON 的语法 JSON(JavaScript Object Notation):是 ECMAScript 的子集。作用是进行数据的交换。语法更为简洁,网络传输、机器解析都更为迅速。 语法规则: 数据在键值对中 数据由逗号分隔 花括号保存对象 方括号保存数组…

算法精讲:选择排序

基本思想 每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在待排序的数列的最前端,直到所有元素排完。 排序过程 初始关键字:【3 1 5 4 2】 第一趟排序后:1【3 5 4 2】 第二趟排序后:1 2【5 4 3】 第三趟排序后:1 2 3【4 5】 最终结果:1 2 3 4 5…

Actions和Mutations

在Vuex中,actions和mutations都是用来改变store中的状态的方法,它们之间的区别如下: Mutations:用于同步地修改state的方法。它们接收state作为第一个参数,并且可以接收额外的参数作为payload。Mutations应该是纯函数&…

yum仓库及NFS共享

yum简介 yum是一个基于RPM包(是Red-Hat Package Manager红帽软件包管理器的缩写)构建的软件更新机制,能够自动解决软件包之间的依赖关系。 yum 实现过程 先在yum服务器上创建 yum repository(仓库),在仓…

使用双指针解决问题题集(二)

1. 有效三角形的个数 给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3 示例 2: 输入: nums [4,2,3,4] 输出: 4 题解&a…

学习软考----数据库系统工程师24

关系数据库设计基础知识 函数依赖 码 多值依赖 性质

nodejs: 将 json 文件中的对象拍平

将 json 文件对象拍平 demo.json {"a": {"b": 123},"c": "abc" }期望将 demo.json 对象拍平 {"a_b": 123,"c": "abc" }源码示例 const fs require(fs);// 读取 JSON 文件 function readJSONFile(f…

迎接AI时代:智能科技的社会责任与未来展望

AI智能体的社会角色、伦理挑战与可持续发展路径 引言: 在技术的浪潮中,AI智能体正逐步成为我们生活的一部分。它们在医疗、教育、交通等领域的应用,预示着一个全新的时代即将到来。本文将结合实际案例和数据分析,深入探讨AI智能体…