任务调度是大多数应用系统的常见需求之一,拿论坛来说:每个半个小时生成精华文章的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. POJ 1151 Atlantis 线段树+离散化+扫描线

    这次是求矩形面积并 /* Problem: 1151 User: 96655 Memory: 716K Time: 0MS Language: G++ Result: Accepted */ #inc ...

  2. 黑盒测试用例设计方法&理论结合实际 -> 场景法

    一概念 现在的软件几乎都是用事件触发来控制流程的,事件触发时的情景便形成了场景,而同一事件不同的触发顺序和处理结果就形成事件流.这种在软件设计方面的思想也可以引入到软件测试中,可以比较生动地描绘出事件 ...

  3. vs2015无法解析外部符号__imp__fprintf

    使用vs2015编译ffmpeg的一个小项时,出现了__imp__fprintf和__imp____iob_func 的错误,google了一下,有的人 建议下载SDL源码重新编译一下,当然这个方案非 ...

  4. js基础第八天

    返回前面起第一个字符位置 indexOf("sdfsdf");它是从左边索引为0开始数,而且只找第一个,然后返回该字符的位置.返回是个数值.如果找不到该字符,那么就会返回-1. 返 ...

  5. js基础第六天

    获取节点属性 getAttribute("属性") 获取属性 setAttribute("属性","值"); 设置节点属性 删除某个属性 r ...

  6. 【暑假】[深入动态规划]UVa 10618 The Bookcase

    UVa 12099  The Bookcase 题目: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=42067 思路:    ...

  7. Kotlin 学习

    http://kotlinlang.cn/ 资料: https://segmentfault.com/a/1190000004494727 http://blog.csdn.net/u01413448 ...

  8. ACM2123(一个简单的问题)

    一个简单的问题 问题说明 在这个问题中,你需要做N * N的乘法表,就像样品.第第i 行和j 个列中的元素i和j的乘积(乘积).   输入 输入的第一行是一个整数C中表示测试用例的数量,然后C的测试用 ...

  9. 【原创】lua的module的一些点

    lua的module好像是5.1开始有的 在xx.lua的开头写上 module('my_module') 这行等价于如下几行 local name = 'my_module' local M = { ...

  10. HW6.4

    import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...