起因:公司做定时处理业务的web应用,跑一段时间会失效,为了查这个原因,去看了下spring scheduler实现原理。
首先我们看看简单定时器实现方法:用ScheduledExecutorService接口
public interface ScheduledExecutorService extends ExecutorService
{
创建并执行在给定延迟后启用的一次性操作。
ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit);
创建并执行在给定延迟后启用的 ScheduledFuture。
<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit);
创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。如果任务的任何一个执行遇到异常,则后续执行都会被取消。否则,只能通过执行程序的取消或终止方法来终止该任务。如果此任务的任何一个执行要花费比其周期更长的时间,则将推迟后续执行,但不会同时执行。
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period, TimeUnit unit);
创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。如果任务的任一执行遇到异常,就会取消后续执行。否则,只能通过执行程序的取消或终止方法来终止该任务。
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);
}
用法示例
以下是一个带方法的类,它设置了 ScheduledExecutorService ,在 1 小时内每 10 秒钟蜂鸣一次:
import static java.util.concurrent.TimeUnit.*;
class BeeperControl {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(1);
public void beepForAnHour() {
final Runnable beeper = new Runnable() {
public void run() { System.out.println("beep"); }
};
final ScheduledFuture<?> beeperHandle =
scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
scheduler.schedule(new Runnable() {
public void run() { beeperHandle.cancel(true); }
}, 60 * 60, SECONDS);
}
}
里面几个方法其中说到的当业务中出现异常后,就不会执行后续定时任务了,所以如果要用ScheduledExecutorService 写一些自己的业务定时任务,务必要知道这点。
再来说说Spring Scheduler。
Spring3.0之后增加了调度器功能, 提供的@Schedule等等注解, 那么它内部是如何实现的呢?
核心类摘要:
1.ScheduledAnnotationBeanPostProcessor
2.ScheduledTaskRegistrar
3.TaskScheduler
4.ReschedulingRunnable
具体说明:
1.ScheduledAnnotationBeanPostProcessor
(1)核心方法:Object postProcessAfterInitialization(final Object bean, String beanName)
功能:负责@Schedule注解的扫描,构建ScheduleTask
(2)核心方法:onApplicationEvent(ContextRefreshedEvent event)
功能:spring容器加载完毕之后调用,ScheduleTask向ScheduledTaskRegistrar中注册, 调用ScheduledTaskRegistrar.afterPropertiesSet()
2.ScheduledTaskRegistrar
(1)核心方法:void afterPropertiesSet()
功能:初始化所有定时器,启动定时器
3.TaskScheduler
主要的实现类有三个 ThreadPoolTaskScheduler, ConcurrentTaskScheduler,TimerManagerTaskScheduler
作用:这些类的作用主要是将task和executor用ReschedulingRunnable包装起来进行生命周期管理。
(1)核心方法:ScheduledFuture schedule(Runnable task, Trigger trigger)
4.ReschedulingRunnable
(1)核心方法:public ScheduledFuture schedule()
(2)核心方法:public void run()
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();
}
}
通过schedule方法及run方法互相调用,再利用ScheduledExecutorService接口的schedule(Runnable command,long delay,TimeUnit unit)单次执行效果,从而实现一定时间重复触发的效果。
以上说的都是以@Scheduled(cron = "0 0 2,13,16 ? * *")和默认配置下执行的,调用的TaskScheduler的ConcurrentTaskScheduler实现类,默认单个线程执行。
要以线程池执行的话,需要配置:
<task:annotation-driven scheduler="myScheduler"/>
<task:scheduler id="myScheduler" pool-size="20"/>
给出几个结论:
调度器本质上还是通过juc的ScheduledExecutorService进行的
调度器启动后你无法通过修改系统时间达到让它马上执行的效果
被@Schedule注解的方法如果有任何Throwable出现, 不会中断后续Task, 默认只会打印Error日志,定时任务不会同时被触发。
分享到:
相关推荐
shiro+SpringMVC+Spring+mybatis+maven+mybatis 自动刷新+ Quartz scheduler 定时器管理
Time定时器、Scheduler定时器:依赖的类包:quartz-1.5.2.jar,quartz-all-1.5.2.jar,quartz-jboss-1.5.2.jar
老外的 spring scheduler 实例 使用注解,比较全比较实用
软件名称:Scheduler v1.0┊定时器┊定时关机重启注销,定时打开文档文件夹,定时运行程序 软件大小:204KB 软件类型:绿色免费软件 适用平台:Windows 作 者:Meron 作者邮箱:meronmee@163.com 软件截图: 软件...
Scheduler 是一个可以设定在指定时间完成一些操作的软件(如:关机,提示等)
超级简单易用的java定时器,1个源程序,一个配置文件,再加一个配置项,完美搞定
本系统结合通过 Spring 来集成 Quartz 。 Quartz 下载地址 : http://grepcode.com/snapshot/repo1.maven.org/maven2/org.quartz-scheduler/quartz/ 表达式 含义 "0 0 12 * * ?" 每天中午十二点触发 "0 15 ...
本资源是一个最新 Spring 4.2.2 集成 Quartz Scheduler 2.2.2 的一个简单的 demo,也是博客《最新 Spring 4.2.2 集成 Quartz Scheduler 2.2.2 任务调度示例》的配套示例项目,该博客地址是:...
Spring Scheduler示例 运行以下命令: mvn clean spring-boot:run 在控制台中看一下: . ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | ...
springboot与scheduler结合的定时任务工具、实例项目,一个比较实用的demo,适合已经学习理论需要进行代码时间的初级程序员学习实用,项目比较简单......
主要介绍了spring定时任务(scheduler)的串行、并行执行实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了Spring TaskScheduler使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
task-examproject:使用Spring Scheduler的任务基础项目
基于 extjs-6.5 scheduler实现的资源甘特图,后台采用springiMVC3.1,包括:新增、修改、删除
NULL 博文链接:https://vista-move.iteye.com/blog/2274246
String 定时任务,可以自行设置具体的执行时间 。比如定时发邮件,定时发布文章,定时发布新闻等 使用时直接注入 @Autowired SchedulerTask schedulerTask; 方法调用: schedulerTask.execute(key,runTime,(key)->{...
分布式系统项目 它有3个项目,其中任务1和任务2相似,而任务2中几乎没有增加。 作业1和作业2说明 运行该项目的步骤: 在您的IDE中将该项目导入为Gradle项目...Spring Scheduler用于安排电子邮件通知。 MongoDb保留民
apache-dolphinscheduler-3.1.4-src.tar.gzapache-dolphinscheduler-3.1.4-src.tar.gzapache-dolphinscheduler-3.1.4-src.tar.gzapache-dolphinscheduler-3.1.4-src.tar.gzapache-dolphinscheduler-3.1.4-src.tar....
dolphinscheduler 1.3.6 编译镜像,用于编译dolphinscheduler
Spring Boot Quartz Scheduler示例:构建电子邮件调度应用 完整的教程: : 要求 Java-1.8.x Maven-3.xx MySQL-5.xx 设定步骤 1.克隆应用程序 git clone ...