`
hstrust
  • 浏览: 45839 次
社区版块
存档分类
最新评论

Spring Scheduler定时器原理分析

阅读更多
     起因:公司做定时处理业务的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日志,定时任务不会同时被触发。


   
分享到:
评论

相关推荐

    spring动态定时器封装

    总结起来,Spring动态定时器封装涉及Spring的定时任务支持、Quartz的使用,以及源码分析等多个方面。通过合理的封装,我们可以灵活地管理和控制系统的定时任务,提升系统的可维护性和扩展性。在实际开发中,理解并...

    spring 定时器

    下面将详细阐述Spring定时器的工作原理、配置方法以及使用场景。 1. **工作原理**: Spring定时器基于`java.util.concurrent.ScheduledExecutorService`接口,它是一个线程池服务,可以用来安排在未来某个时间点...

    Sping定时器的使用

    标签中提到的“源码”,意味着深入理解Spring定时任务的实现原理,这可能涉及对Spring源码的阅读。Spring源码中的`org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor`处理`@...

    spring quartz 表达式在线生成器

    标签中的“源码”可能意味着博客或工具会涉及Quartz和Spring的源代码解析,帮助读者理解内部工作原理。而“工具”则表明这是一个实用的开发辅助软件,可以帮助开发者提高效率。 由于没有具体的压缩包文件名称列表,...

    定时器 quartz 和 spring

    标题 "定时器 quartz 和 spring" 涉及到的是两个在Java开发中非常重要的框架——Quartz和Spring。Quartz是一个开源的工作调度框架,它允许开发者创建、调度和执行任务,而Spring则是一个功能丰富的应用程序框架,...

    quartz定时器源码jar包下载

    6. **并发与线程管理**:Quartz在多线程环境下运行,分析`org.quartz.core.QuartzSchedulerThread`,了解其内部调度机制。 7. **插件系统**:Quartz有一个强大的插件系统,如`org.quartz.plugins.history....

    Spring MVC示例

    提供的定时器功能可能使用了`java.util.Timer`或Spring的`org.springframework.scheduling.timer`包,用于定期执行某些任务,如数据清理、统计分析等。在Spring中,也可以使用`@Scheduled`注解配合`TaskScheduler`...

    spring、Quart 源码

    在源码中,你可以看到Spring如何通过Bean容器管理对象的生命周期,以及AOP是如何实现的,这有助于理解其工作原理。 Quartz是Java平台上的一个开源作业调度框架,用于执行周期性或一次性任务。Quartz允许开发者定义...

    定时器quartz的应用

    5. **源码分析**:标签中的"源码"可能意味着文章涉及了Quartz的内部工作原理。Quartz的源码结构清晰,适合学习和扩展,开发者可以通过阅读源码了解其调度算法、存储策略等核心细节。 6. **工具化应用**:作为一款...

    Quartz/J2EE (定时服务)

    源码分析是理解Quartz工作原理的关键,通过阅读源码,我们可以深入理解Job、Trigger和Scheduler之间的协作机制,以及Quartz如何调度和执行任务。例如,Quartz使用了PriorityBlockingQueue来存储待执行的任务,保证了...

    taskScheduler

    通过阅读和分析这些文件,我们可以了解到taskScheduler的具体实现细节,例如它如何使用Java API与Flow服务器交互,如何定义任务调度规则,以及如何处理协作和队列任务。 5. **应用实例** 例如,taskScheduler可能...

    quartz例子

    2. **Trigger**:触发器定义了Job何时执行,它可以是简单的定时器,也可以是复杂的CRON表达式。 3. **Scheduler**:调度器负责安排和管理Job与Trigger的关系,决定何时运行哪个Job。 Quartz的工作流程如下: 1. **...

    爬虫搜索,简单的搜索引擎,java爬虫,搜索引擎例子,爬虫demo,java实现互联网内容抓取,搜索引擎大揭密

    对于定时任务,可以结合Quartz或Spring Scheduler等框架实现周期性的网页抓取。 例如,`demo`可能是一个简单的Java爬虫程序示例,它可能包括以下几个关键步骤: 1. **初始化配置**:设置起始URL、爬取深度、延迟...

Global site tag (gtag.js) - Google Analytics