在用spring定时任务时,配置如下:
<task:executor id="executor" pool-size="5" />
<task:scheduler id="scheduler" pool-size="10" />
<task:annotation-driven executor="executor" scheduler="scheduler" />
配置项schema为spring-task-3.0.xsd。
对某方法定义cron如下:
@Scheduled(cron = "0 */5 * * * ?")
pulic void run(){
//other codes…
}
因run方法是每5分钟跑一次,而run方法中具有复杂的业务逻辑(大概包括调用第三方httpservice,导数据到内存计算,再分次批量写库)。Task可能会运行超过5分钟,此种情况下,预期目标是和linux cron一样,定点执行task,而不用理会前一个task是否已完成。
运行一段时间后,发现少了几个点的数据,然后针对数据查看了相应的日志,发现每次都只会有一个shedule线程跑同一个run方法,而这个run方法处于wait状态或5分钟内没跑完,会导致后续的task不能按时启动。
查看spring源码,shedule流程初始化如下:
1.在bean初始化后,通过反射机制,对实例化的bean的class进行注解扫描,判断bean的class定义中@Scheduled注解。若有则判断调度模式,如本题中为cron调度模式。此实现代码位于:
ScheduledAnnotationBeanPostProcessor.postProcessAfterInitialization
在扫描到@Scheduled的方法后,把每一个目标method封装为Runnable,代码如下:
MethodInvokingRunnable runnable = new MethodInvokingRunnable();
runnable.setTargetObject(bean);
runnable.setTargetMethod(method.getName());
runnable.setArguments(new Object[0]);
try {
runnable.prepare();
}
catch (Exception ex) {
throw new IllegalStateException("failed to prepare task", ex);
}
此postProcessAfterInitialization是维护crontasks,fixedRateTasks容器,针对每一个目标method生成相应的MethodInvokingRunnable对实例。
2.针对cron任务,对每一个MethodInvokingRunnable注册相应的CronTrigger,并通过ConcurrentTaskSchedule.shedule创建ReschedulingRunnable执行器并解析cron表达式添加第1个task。
代码实现在ScheduledTaskRegistrar. afterPropertiesSet。
3. ReschedulingRunnable自身 串联schdule。如下代码所示:
public ScheduledFuture schedule() {
synchronized (this.triggerContextMonitor) {
this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
if (this.scheduledExecutionTime == null) {
return null;
}
long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
return this;
}
}
@Override
public void run() {
Date actualExecutionTime = new Date();
super.run();
Date completionTime = new Date();
synchronized (this.triggerContextMonitor) {
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
}
if (!this.currentFuture.isCancelled()) {
schedule();
}
}
其中trigger.nextExecutionTime即获取下一个task的执行时间,并提交到executor执行器。
而见run中,是执行了当前的task后再根据corn表达式获取下一个时间点。如此若当前task超过5分钟则下一个5分钟时间点的任务不会被执行。而想要达到linux cron形式的task调度,则需要在此基础之上进行简单处理。
处理办法:
额外创建一个线程池executor如名称为A,在cron方法中提交runnable给这个A执行。
这样的情况可以满足和linux cron一样的定时需求,但得对task有独立性要求。若前后有存在依赖,或者可能导致数据一致性问题还是得慎重。
ps:依据spring中根据bean来解析相应class的schedule注解,如果相应class的实例为多个,就会导致同时有多个相同的task执行。
分享到:
相关推荐
win Cron定时任务
CRON定时任务生成工具CRON定时任务生成工具CRON定时任务生成工具CRON定时任务生成工具CRON定时任务生成工具CRON定时任务生成工具CRON定时任务生成工具
8 import org.springframework.util.Assert; 9 10 import java.text.ParseException; 11 import java.util.Date; 12 import java.util.List; 13 14 /** 15 * *******************************************...
windows本地监控任务cron定时任务软件.本地监控软件,可设置定时访问指定网址
在不停服务的情况下,动态修改Spring定时任务的执行周期,即动态修改定时任务的cron参数。
vue3+ts+naive UI,有执行时间的中文解析,还有10次执行时间(需要后端写接口). 1.将文件放在你想放的项目文件夹下,引入import vue3CronComponent from "xxxx";如果需要中文解析功能,同理引入即可。 3.需要传的值...
spring定时器cron表达式生成
gocron - 使用Go语言开发的轻量级定时任务集中调度和管理系统, 用于替代Linux-crontab
用Java写的Cron表达式解析, Java swing编写的简洁界面,表达式到界面,界面到表达式,实现双重解析
cron定时任务,用来在Linux使用创建定时任务,本文档有详细的使用过程和检验结果
树莓派+cron定时执行任务,实行任务的自动化定时化执行
Spring+Quartz 从数据库中获取定时任务和定时时间,动态实现对定时任务的增删改查,部署到tomcat即可看到定时任务执行效果。本人亲测,可用!
前端Corn定时任务表达式以及反解析功能,使用 antD框架js写法
Spring + quartz 定时任务修改定时时间不重启服务
Spring boot开启定时任务的三种方式 零、前言 第一种也就是最简单的一种:基于注解 (@Scheduled)的方式; 第二种:基于接口 (SchedulingConfigurer); 第三种:基于注解设定多线程定时任务。 一、基于@Scheduled注解...
spring cron 定时任务配置
本例中一共使用了两种 spring 的定时任务,一种是使用 xml 配置的定时任务,一种是使用 annotation 配置的定时任务,其中后者的 cronExpress 表达式是配置在配置文件中的,两者的区别在于,xml是比较传统的方式,...
c++任务调度,Bosma::Scheduler 支持cron表达式
cron定时执行脚本
资源为js文件,下载后直接用script标签引入,需要解析时调用该js第一个方法,参数为cron定时器表达式字符串,例如:translateCRONToChinese("0 0 12 */1 * ?");