zoukankan      html  css  js  c++  java
  • pring Scheduler定时器原理分析

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

    Java代码  
    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 秒钟蜂鸣一次: 
      

    Java代码  
    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() 

    Java代码  
     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;  
        }  
    }  
    Java代码 
    @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日志,定时任务不会同时被触发。 

  • 相关阅读:
    HTML5之viewport使用
    css position小结
    图片预加载
    ie6 双边距问题
    json化的必要性
    nginx配置详解(转)
    nginx技术分享 (转)
    js 解决图片居中问题
    NGUI panel使用soft clip时,屏幕缩放后无法正常工作的问题解决
    使用代码修改camera.cullingMask
  • 原文地址:https://www.cnblogs.com/AnXinliang/p/9958335.html
Copyright © 2011-2022 走看看