Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。Jobs可以做成标准的Java组件或 EJBs。
http://www.ibm.com/developerworks/cn/java/j-quartz/
http://www.ibm.com/developerworks/cn/java/j-lo-taskschedule/
官网:http://www.quartz-scheduler.org/
官网文档:http://www.quartz-scheduler.org/documentation
开源中国:http://www.oschina.net/p/quartz
百度百科:http://baike.baidu.com/subview/1002067/5810766.htm#viewPageContent
|
(1)Quartz 调度包的两个基本单元是作业和触发器。作业是能够调度的可执行任务,触发器 提供了对作业的调度。
(2)Quartz 允许在不丢失作业本身或作业的上下文的情况下,修改调度触发器。而且,任何单个的作业都可以有多个触发器与其关联。
package com.mcc.core.quartz;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
/**
* 任务调度器服务,用到quartz包
*
* @author menergy
* DateTime: 13-12-20 上午10:54
*/
public abstract class ScheduleService {
// members
private static Logger logger = LoggerFactory.getLogger(ScheduleService.class);
// 任务调度器
protected Scheduler scheduler;
// static block
// constructors
// properties
// public methods
/**
* 添加任务调度器
*
* @param scheduler 调度器
*/
public abstract void addScheduler(Scheduler scheduler);
/**
* 通用执行任务方法,并按照cronExpression执行任务
*
* @param jobClazz 执行的任务类
* @param groupName JOB组
* @param cronExpression cron表达式
* @throws org.quartz.SchedulerException
* @throws java.text.ParseException
*/
public void addJob(Class jobClazz, String groupName, String cronExpression) throws SchedulerException, ParseException {
addJob(jobClazz, groupName, cronExpression, false);
}
/**
* 通用执行任务方法,并按照cronExpression执行任务
*
* @param jobClazz 执行的任务类
* @param groupName JOB组
* @param cronExpression cron表达式
* @param pause 是否默认暂停
* @throws org.quartz.SchedulerException
* @throws java.text.ParseException
*/
public void addJob(Class jobClazz, String groupName, String cronExpression, boolean pause) throws SchedulerException, ParseException {
addJob(null, jobClazz, groupName, cronExpression, pause);
}
/**
* 通用执行任务方法,并按照cronExpression执行任务
*
* @param jobDetail 执行的任务
* @param jobClazz 执行的任务类
* @param groupName JOB组
* @param cronExpression cron表达式
* @throws org.quartz.SchedulerException
* @throws java.text.ParseException
*/
public void addJob(JobDetail jobDetail, Class jobClazz, String groupName, String cronExpression) throws SchedulerException, ParseException {
addJob(jobDetail, jobClazz, groupName, cronExpression, false);
}
/**
* 通用执行任务方法,并按照cronExpression执行任务
*
* @param jobDetail 执行的任务
* @param jobClazz 执行的任务类
* @param groupName JOB组, jobName = groupName + "_DETAIL", triggerName = groupName + "_TRIGGER"
* @param cronExpression cron表达式
* @param pause 是否默认暂停
* @throws org.quartz.SchedulerException
* @throws java.text.ParseException
*/
public void addJob(JobDetail jobDetail, Class jobClazz, String groupName, String cronExpression, boolean pause) throws SchedulerException, ParseException {
// 添加任务
String jobName = new StringBuilder(groupName).append("_").append("DETAIL").toString();
if (jobDetail == null) {
jobDetail = new JobDetail();
}
if (groupName == null || groupName.isEmpty()) {
groupName = Scheduler.DEFAULT_GROUP;
}
jobDetail.setName(jobName);
jobDetail.setGroup(groupName);
jobDetail.setJobClass(jobClazz);
scheduler.addJob(jobDetail, true);
// 添加解发器
String triggerName = new StringBuilder(groupName).append("_").append("TRIGGER").toString();
CronTrigger cronTrigger = new CronTrigger();
cronTrigger.setName(triggerName);
cronTrigger.setGroup(groupName);
cronTrigger.setJobName(jobDetail.getName());
cronTrigger.setJobGroup(groupName);
cronTrigger.setCronExpression(cronExpression);
scheduler.scheduleJob(cronTrigger);
if (pause) {
scheduler.pauseJob(jobName, groupName);
}
}
/**
* 暂停所有任务
*
* @throws org.quartz.SchedulerException
*/
public void pausehAll() {
try {
scheduler.pauseAll();
} catch (SchedulerException e) {
logger.error("暂停所有任务失败!", e);
}
}
/**
* 暂停指定JOB
*
* @param jobName JOB名称
* @throws org.quartz.SchedulerException
*/
public void pauseJob(String jobName) {
pauseJob(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 暂停指定JOB
*
* @param jobName JOB名称
* @throws org.quartz.SchedulerException
*/
public void pauseJob(String jobName, String groupName) {
try {
scheduler.pauseJob(jobName, groupName);
} catch (SchedulerException e) {
logger.error("暂停任务 " + jobName + " 失败!", e);
}
}
/**
* 暂停指定JOB Group
*
* @param groupName 组名
* @throws org.quartz.SchedulerException
*/
public void pauseGroup(String groupName) {
try {
scheduler.pauseJobGroup(groupName);
} catch (SchedulerException e) {
logger.error("暂停任务组 " + groupName + " 失败!", e);
}
}
/**
* 恢复所有JOB
*
* @throws org.quartz.SchedulerException
*/
public void resumeAll() {
try {
scheduler.resumeAll();
} catch (SchedulerException e) {
logger.error("恢复所有任务失败!", e);
}
}
/**
* 恢复指定JOB
*
* @param jobName JOB名称
* @throws org.quartz.SchedulerException
*/
public void resumeJob(String jobName) {
resumeJob(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 恢复指定JOB
*
* @param jobName JOB名称
* @throws org.quartz.SchedulerException
*/
public void resumeJob(String jobName, String groupName) {
try {
scheduler.resumeJob(jobName, groupName);
} catch (SchedulerException e) {
logger.error("恢复任务 " + jobName + " 失败!", e);
}
}
/**
* 恢复指定JOB Group
*
* @param groupName 组名
*/
public void resumeGroup(String groupName) {
try {
scheduler.resumeJobGroup(groupName);
} catch (SchedulerException e) {
logger.error("恢复任务组失败!", e);
}
}
/**
* 获取JOB
*
* @param jobName JOB名称
* @return
* @throws org.quartz.SchedulerException
*/
public JobDetail getJobDetail(String jobName) throws SchedulerException {
return scheduler.getJobDetail(jobName, Scheduler.DEFAULT_GROUP);
}
/**
* 启动调度器
*
* @throws org.quartz.SchedulerException
*/
public void start() throws SchedulerException {
scheduler.start();
}
/**
* 停止调度器
*
* @throws org.quartz.SchedulerException
*/
public void stop() throws SchedulerException {
scheduler.shutdown();
}
// protected methods
// friendly methods
// private methods
// inner class
// test main
}
package com.mcc.core.test;
import com.mcc.core.quartz.ScheduleService;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;
import java.text.ParseException;
/**
* quartz任务调度测试
*
* @author menergy
* DateTime: 13-12-20 下午12:49
*/
public class QuartzTest extends ScheduleService {
@Override
public void addScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
public void execute(){
// 设置调度器
try {
addScheduler(StdSchedulerFactory.getDefaultScheduler());
try {
//可以一次执行多个addJob
this.addJob(TestJob.class,"test","0/2 * * * * ?");
this.start();
} catch (ParseException e) {
e.printStackTrace();
}
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public static void main(String args[]){
new QuartzTest().execute();
}
}
1)使用 Timer 实现任务调度的核心类是 Timer 和 TimerTask。其中 Timer 负责设定 TimerTask 的起始与间隔执行时间。使用者只需要创建一个 TimerTask 的继承类,实现自己的 run 方法,然后将其丢给 Timer 去执行即可。
2)Timer 的设计核心是一个 TaskList 和一个 TaskThread。Timer 将接收到的任务丢到自己的 TaskList 中,TaskList 按照 Task 的最初执行时间进行排序。TimerThread 在创建 Timer 时会启动成为一个守护线程。这个线程会轮询所有任务,找到一个最近要执行的任务,然后休眠,当到达最近要执行任务的开始时间点,TimerThread 被唤醒并执行该任务。之后 TimerThread 更新最近一个要执行的任务,继续休眠。
3)Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
package com.mcc.core.test;
import java.util.Timer;
import java.util.TimerTask;
/**
* 串行作业调度Timer测试类
*
* @author menergy
* DateTime: 14-2-12 下午4:52
*/
public class TimerTest extends TimerTask {
private String jobName = "";
public TimerTest(String jobName) {
super();
this.jobName = jobName;
}
@Override
public void run() {
System.out.println("运行作业: " + jobName + ",开始");
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("运行作业: " + jobName + ",完成");
}
public static void main(String args[]){
Timer timer = new Timer();
// 从现在开始 5 秒钟之后,每隔 1 秒钟执行一次 job1
timer.schedule(new TimerTest("job1"), 5000, 1000);
// 从现在开始 1 秒钟之后,每隔 2 秒钟执行一次 job2
timer.schedule(new TimerTest("job2"), 1000, 2000);
}
}
2)ScheduledExecutorService 中两种最常用的调度方法 ScheduleAtFixedRate 和 ScheduleWithFixedDelay。
ScheduleAtFixedRate 每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为 :initialDelay, initialDelay+period, initialDelay+2*period, …;
ScheduleWithFixedDelay 每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay, initialDelay+executeTime+delay, initialDelay+2*executeTime+2*delay。
由此可见,ScheduleAtFixedRate 是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay 取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。
package com.mcc.core.test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 并发任务调度ScheduledExecutor测试类
*
*
* @author menergy
* DateTime: 14-2-12 下午5:05
*/
public class ScheduledExecutorTest implements Runnable{
private String jobName = "";
public ScheduledExecutorTest(String jobName) {
super();
this.jobName = jobName;
}
@Override
public void run() {
System.out.println("运行作业: " + jobName + ",开始");
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("运行作业: " + jobName + ",完成");
}
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(3);
long initialDelay1 = 1;
long period1 = 1;
// 从现在开始1秒钟之后,每隔1秒钟执行一次job1 ,固定时间模式
service.scheduleAtFixedRate(
new ScheduledExecutorTest("job1"),
initialDelay1,period1, TimeUnit.SECONDS);
long initialDelay2 = 2;
long delay2 = 2;
// 从现在开始2秒钟之后,每隔2秒钟执行一次job2 ,不固定时间模式
service.scheduleWithFixedDelay(
new ScheduledExecutorTest("job2"),
initialDelay2,delay2, TimeUnit.SECONDS);
}
}