zno2

深入了解定时任务(一)

单词辅助记忆

scheduled  车堵了?

 

线索

java.util.concurrent.Future<V>
site:spring.io task
https://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/scheduling.html
org.springframework.scheduling.support.CronTrigger
org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor
org.springframework.scheduling.annotation.EnableScheduling
org.springframework.scheduling.concurrent.ReschedulingRunnable(循环核心类)

 


更好粒度的控制,可以使用 SchedulingConfigurer
For more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces


@EnableScheduling 说白了就是在配置SchedulingConfigurer,通过注解和反射注册任务

关键点是 org.springframework.scheduling.config.ScheduledTask.cancel()
这个是注销之前的任务
然后在注册一个任务,就相当于更新任务
spring已经对 jdk 中 java.util.concurrent.ScheduledFuture<?> 进行了一层封装
动态任务这里只需要对接spring即可

 

QA

问:trigger 如何一次又一次被触发呢?
答:org.springframework.scheduling.concurrent.ReschedulingRunnable
具体栈:
void ScheduledTaskRegistrar.afterPropertiesSet()
void ScheduledTaskRegistrar.scheduleTasks()
ScheduledTask ScheduledTaskRegistrar.scheduleCronTask(CronTask task)
return new ReschedulingRunnable(task, trigger, executor, errorHandler).schedule();
// 重新调度,每次调度之后会计算下次调度时间,延迟触发后,重新调度
// 它主要是计算下一次触发时间,调用被代理的任务(super.run()),完毕后更新触发上下文信息,再次调用schedule(),重新生成一个java.util.concurrent.ScheduledFuture<?>
循环逻辑是:首次调用schedule -> 计算延迟-> 生成future-> 等待run() -> 调用super.run()执行真实业务 -> 如果没有cancel则再调用schedule,如此循环
org.springframework.scheduling.concurrent.ReschedulingRunnable(核心类)
java.util.concurrent.ScheduledThreadPoolExecutor
java.util.concurrent.ScheduledThreadPoolExecutor.DelayedWorkQueue

 

问:如果下次n2执行时间点在本次n1执行过程中,如何触发,会舍弃n2执行n3吗?
答:CronTrigger 不会,实际测试 @Scheduled(cron = "1,2,3 * * * * *") ,执行时sleep 2秒只触发一次。org.springframework.scheduling.support.CronTrigger.nextExecutionTime(TriggerContext) 说明中也明确指出 Next execution times are calculated based on the completion time of theprevious execution; therefore, overlapping executions won't occur.

 

问:@Scheduled 注解方法支持传入上下文吗?
答:不支持,Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'job1': Only no-arg methods may be annotated with @Scheduled

 

问:spring.task.scheduling.pool.size 是用来控制什么的?
答:对应的配置类是 org.springframework.boot.autoconfigure.task.TaskExecutionProperties
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
。指同时执行的任务数,一个任务对应一个future,即便线程是1,两个任务也会先后触发。单个cron任务遵循重叠不执行 。

 


问:动态定时任务思路

答:动态定时任务是指通过UI展示任务列表及执行状态,按需启动、暂停、注销任务,修改任务触发时间
具体思路:
1 spring 通过注解和反射配置任务执行器和任务调度器,扫描所有可执行任务
2 禁用 @EnableScheduling 注解
3 自定义 SchedulingConfigurer
4 起一个特殊的定时任务,检测任务信息是否发生变化,如果发生变化先cancel 后 schedule
5 任务信息持久化

难点:如何复用spring properties配置的 执行器,调度器和注解配置的可执行任务

demo 实现一个简单的启动、暂停、注销任务和修改任务触发时间

 

类图

备注①:这个类为了方便理解展示自行添加,实际是内部类 java.util.concurrent.ScheduledThreadPoolExecutor.ScheduledFutureTask<V>
备注②:这个类是spring 和 jdk 的纽带,是代理模式,代理 java.util.concurrent.ScheduledFuture<?>
备注③:这个类是spring关键类,在这里编排任务,绑定 jdk ScheduledFuture 到 spring ScheduledTask

 

任务触发时堆栈

 

posted on 2023-06-02 08:07  zno2  阅读(41)  评论(0编辑  收藏  举报

导航