注解定时器_Spring Scheduler定时器原理分析

本文介绍了如何使用ScheduledExecutorService创建定时任务,并强调了当业务中出现异常时,定时任务将不会继续执行的重要性。接着探讨了Spring Scheduler的内部实现,包括ScheduledAnnotationBeanPostProcessor、ScheduledTaskRegistrar、TaskScheduler和ReschedulingRunnable等关键类的作用。Spring的@Scheduled注解基于ScheduledExecutorService实现,即使出现异常,定时任务也不会被中断,只会记录错误日志。
摘要由CSDN通过智能技术生成

首先我们看看简单定时器实现方法:用ScheduledExecutorService接口

public  interface ScheduledExecutorService extends ExecutorService

{

  创建并执行在给定延迟后启用的一次性操作。

 ScheduledFuture> schedule(Runnable command,long delay,TimeUnit unit);

创建并执行在给定延迟后启用的 ScheduledFuture。

ScheduledFuture schedule(Callable 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);

    }

 }

[color=red]里面几个方法其中说到的当业务中出现异常后,就不会执行后续定时任务了,所以如果要用ScheduledExecutorService 写一些自己的业务定时任务,务必要知道这点。[/color]

再来说说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)单次执行效果,从而实现一定时间重复触发的效果。

06ec9a34ac958bcade7c337ddf1948b8.png

以上说的都是以@Scheduled(cron = "0 0 2,13,16 ? * *")和默认配置下执行的,调用的TaskScheduler的ConcurrentTaskScheduler实现类,默认单个线程执行。

要以线程池执行的话,需要配置:

给出几个结论:

调度器本质上还是通过juc的ScheduledExecutorService进行的

调度器启动后你无法通过修改系统时间达到让它马上执行的效果

被@Schedule注解的方法如果有任何Throwable出现, 不会中断后续Task, 默认只会打印Error日志,定时任务不会同时被触发。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值