任务调度是大多数应用系统的常见需求之一,拿论坛来说:每个半个小时生成精华文章的RSS文件,每天凌晨统计论坛用户的积分排名,每隔30分钟执行对锁定过期的用户进行解锁。以上都是以时间为关注点的调度,事实上我们在实际中还会使用资源上的调度,如线程的使用。spring提供了Quartz,Timer,Executor的支持,使得使用时更加简化。

一、Quartz

1.Quartz提供了强大的任务调度机制,提出了调度器、任务、触发器这三个核心概念。

Job: 是一个接口,只有一个执行方法,开发者想要完成什么任务,可以自己实现。

JobDetail: 描述Job实现类及其他静态信息,Quartz每次执行job时,都是创建一个job实例。

Trigger: 其来触发Job执行的时间触发规则,主要有SimpleTrigger和CronTrigger两个子类。

Scheduler: Quartz运行的一个独立容器。Trigger和JobDetail可以注册进来,其允许外部通过接口方法来访问它们。 通过SchedulerFactory创建一个Scheduler实例,其拥有一个SchedulerContext,保存上下文信息。

任务的信息保存在JobDataMap实例中,Job有个StatefulJob子接口,对于该有状态的任务,任务对JobDataMap的更改会保存下来影响后续的执行,因此不能并发执行。而无状态的job可以并发执行。如图所示:

默认情况下,Quartz的运行信息是保存在内存中的,因为内存中的数据访问最快。如果需要持久化任务调度信息,Quartz允许用户通过调整其属性文件,将信息保存到数据库中。

2.spring中的Quartz

spring为创建Quartz中的Scheduler、Trigger和JobDetail提供了变量的FactoryBean类,首先看实例配置:

<bean id="myService" class="org.slob.service.MyService"></bean>

    <bean id="quartzTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject">
            <ref bean="myService" />
        </property>
        <property name="targetMethod">
            <value>quartzJob</value>
        </property>
    </bean>     <bean id="quartzTaskTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail">
            <ref bean="quartzTask" />
        </property>
        <property name="cronExpression">
            <value>${cron.expression}</value>
        </property>
    </bean>     <bean id="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="quartzTaskTrigger" />
            </list>
        </property>
    </bean>
    

在实例中我们周期执行的是myService中的quartzJob方法,执行的周期由${cron.expression}来指定。在此trigger为CronTriggerBean,然后开启调度器startQuartz。

下面介绍cron expression的格式:

一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素,从左到右为:

0-59     0-59        0-23    1-31     1-12(*)     1-7(*)   1970-2099

每个元素都显示规定一个值,一个区间 " - " ,一个列表或通配符;一个问号表示不想设置该字段(在星期和日期中使用),“/"字符用于指定增量,如如:“0/15”在秒域意思是每分钟的0,15,30和45秒。其中"L" 在月字段表示该月的最后一天,在周字段表示SAT或7,;"W"只会在日期中出现表示工作日;"#" 只会在星期字段中出现,用于指定本月的某某天,如“6#3”表示本月第三周的星期五(6表示星期五,3表示第三周);"C "在日期和星期字段中出现,这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历”关联,则等价于所有包含的“日历”。如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)。

如表达式:

“10 */1 * * * ?”意为:从10秒开始,每1分钟执行一次

"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发

"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发

"0 15 10 L * ?" 每月最后一日的上午10:15触发

"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发

"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发

二、Java Timer

1.Java通过java.util.Timer和java.util.TimerTask这两个类提供了简单的任务调度功能,允许按照固定频率重复执行某项任务,其只适合对执行时间非常短的任务进行调度,因为TimerTask都在同一背景线程中执行,长时间的任务会严重影响Timer的调度工作。因为如果一个TimerTask的执行占用了过多的时间,后面的任务就会受到影响,在调度时间轴上受到了“挤压”,可能会造成“扎堆”执行的情况。

TimerTask实现了Runnable接口, 我们自己在run()方法中定义任务逻辑,Timer负责制定规则并调度TimerTask。

2.spring中的Timer

spring提供了JDK Timer支持,更加方便使用timer,实力配置如下:

<bean id="myService" class="org.slob.service.MyService"/>

    <bean id="timerTask" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
        <property name="targetObject">
            <ref bean="myService"/>
        </property>
        <property name="targetMethod">
            <value>timerJob</value>
        </property>
    </bean>
    <bean id="scheduleTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">   
        <property name="timerTask" ref="timerTask" />   
        <property name="delay">
            <value>300000</value>
        </property>
        <property name="period">   
            <value>86400000</value>   
        </property>   
    </bean>  
    <bean class="org.springframework.scheduling.timer.TimerFactoryBean">   
        <property name="scheduledTimerTasks">   
               <list>
                   <ref bean="scheduleTask"/>
               </list>   
        </property>  
    </bean>

该配置在延迟5分钟后,每个24小时执行一次myService中的timerJob方法,如果更加细致的调度,则timer显得力不从心!

三、Jdk Executor

1. JDK5.0中的java.util.concurrent包,提供了功能强大、更高层次的线程构造器。执行器Executor是并发工具包中的一个重要的类,它对Runnable实例的执行进行了抽象,实现者可以提供具体的实现:如简单的以一个线程来运行Runnable,或者通过一个线程池为Runnable提供共享线程。其将“任务提交”和“任务执行”两者分离解耦。

Executor只有一个方法:void execute(Runnable command),接收实现了Runnable的实例,代表了一个待执行的任务。Executor接口还有两个子接口:ExecutorService和SchedulerExecutorService,前者添加了结束任务的管理方法,后者可以对任务进行调度。

JDK ThreadPoolExecutor类实现了Executor和ExecutorService接口,其使用线程池对任务进行调度。 创建线程的开销较大,因此最好能重用同一个线程,动态创建线程池中的线程,防止资源消耗引发的系统性能问题。ThreadPoolExecutor的子类ScheduledThreadPoolExecutor实现ScheduledExecutorService接口,添加了对人物的调度功能。

java.util.concurrent中提供了一个综合性的工厂类Executors,它拥有很多静态工厂方法:

public static ExecutorService newFixedThreadPool(int nThreads):创建一个线程池,重复使用一个固定的线程运行一个共享的无界队列。

public static ExecutorService  newCachedThreadPool():线程池是动态的,不够用时创建新的线程,长时间不用的线程将被回收。

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize,ThreadFactory threadFactory):创建一个线程池,可在指定延迟后运行或者定期地执行。

2.spring与executor

spring的发现包中预定义了一些TaskExecutor实现。org.springframework.core.task.TaskExecutor接口的实现类很多,且有一个子接口SchedulingTaskExecutor。

SyncTaskExecutor:该实现不会异步执行任务,每次调用都在发起调用的主线程中。

下面是SchedulingTaskExecutor的实现类:

SimpleAsynTaskExecutor:这个实现没有实现使用线程池,在每次执行任务时都创建一个新线程,支持对并发总数设限

ConcurrentTaskExecutor:该类是JDK Executor的适配器,以便将JDK Executor当成spring的TaskExecutor使用

SimpleThreadPoolTaskExecutor:其是SimpleThreadPool的子类,监听spring的生命周期回调,当用户有线程池,需要Quartz和非Quartz组件中共用时,其发挥作用。

ThreadPoolTaskExecutor:其只可在JDK 5.0中使用,方便spring中配置一个ThreadPoolExecutor,并把它包装成TaskExecutor

TimerTaskExecutor:该类使用一个Timer作为其后台的实现。

Spring任务调度的更多相关文章

  1. spring 任务调度quartz

    简单记录一下spring任务调度quartz的例子 首先添加包 quartz-2.2.3.jar 然后写个简单的TestJob类 package com.job; import java.util.D ...

  2. Spring任务调度之Quartz

    一.Quartz作业类的继承方式来讲,可以分为两类: 作业类需要继承自特定的作业类基类,如Quartz中需要继承自org.springframework.scheduling.quartz.Quart ...

  3. Spring任务调度之Timer

    一.分类 由于现在大部分的系统都是采用了spring,所以所有的例子都结合spring来构建,目前主要的任务调度分为三种: Java自带的java.util.Timer类,这个类允许你调度一个java ...

  4. Spring任务调度器之Task的使用

    Spring Task提供两种方式进行配置,正如大家所想吧,还是一种是annotation(标注),而另外一种就是XML配置了.但其实这里我觉得比较尴尬,因为任务调度这样的需求,通常改动都是比较多的, ...

  5. Spring(十)Spring任务调度

    一.计划任务 需要定时执行一些计划(定时更新等),这样的计划称之为计划任务 Spring抽象封装了Java提供的Timer与TimerTask类 也可以使用拥有更多任务计划功能的Quartz 二.Ti ...

  6. Spring任务调度之Quartz集成

    推荐一个博客:http://blog.csdn.net/column/details/14251.html 基本概念 Job:是一个接口,只有一个方法void execute(JobExecution ...

  7. Spring任务调度器之Task的使用(转)

    文章转自 http://blog.csdn.net/l454822901/article/details/51829307 最近发现真的凹凸了,spring升级到3后原来已经自带任务调度器了,之前还一 ...

  8. Spring任务调度实战之Quartz Simple Trigger(转)

     启动时执行和定时执行: 本文地址:http://blog.csdn.net/kongxx/article/details/6751300 在spring中对任务调度的集成除了使用JDK自带的Time ...

  9. Spring任务调度<task:scheduled-tasks>【含cron参数详解】 (转载)

    Spring内部有一个task是Spring自带的一个设定时间自动任务调度 task使用的时候很方便,但是他能做的东西不如quartz那么的多! 可以使用注解和配置两种方式,配置的方式如下 引入Spr ...

随机推荐

  1. 再见WCF

    转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式.记得从自己最开始做MFC时,就使用过Named Pipe命名管道,之后做Winfo ...

  2. Parallel for-each loops in .NET C# z

    An IEnumerable object An Action of T which is used to process each item in the list List<string&g ...

  3. 第一章 :绪论-Twitter数据的收集和处理

    为什么要用twitter,我心里是一万头CNM在飞奔.这个国外的东西很不好访问到的,国内的政策,你懂的,不说这个了,还是想办法翻出去再说吧. 不知道别人都用的什么工具,看到太多的注册就头大,就选了一个 ...

  4. bzoj 3130 [Sdoi2013]费用流(二分,最大流)

    Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识.    最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络 ...

  5. Android字符串相关类 - CharSequence

    Class Overview CharSequence定义为public interface.该接口用于表示一个有序字符的集合,并在其中定义里了处理字符的方法. 已知的常用间接子类有String, S ...

  6. leetcode@ [274/275] H-Index & H-Index II (Binary Search & Array)

    https://leetcode.com/problems/h-index/ Given an array of citations (each citation is a non-negative ...

  7. Excel里的单元格提行

    最近老板发了个表,遇到了个小知识点,收藏以后有用!拿来学学 如下,是属于单元格.怎么提行? 直接,空格或space,都无法解决!...... 解决办法:Alt + Enter 成功! 参考: http ...

  8. 松下蓄电池与UPS使用和维护

      使用条件及环境1.充电电流(浮充使用):0.15CA以下2.放电电流范围:0.05CA-3CA3.环境温度:0℃-40℃ (适宜的温度是25℃) 4.充电电压:(12V电池推荐值)   周围温度 ...

  9. [iOS基础控件 - 6.8] 各种数据类型的@property属性

    A.内存管理 NSString: copy 基本数据类型.结构体(int, CGFloat, BOOL, CGRect等):assign 对象(如自定义model类型.NSArray.NSDictio ...

  10. swift 内存管理,WEAK 和 UNOWNED

    因为 Playground 本身会持有所有声明在其中的东西,因此本节中的示例代码需要在 Xcode 项目环境中运行.在 Playground 中可能无法得到正确的结果. 不管在什么语言里,内存管理的内 ...