一个任务或作业定时执行需求在我们的系统中普遍存在,Quartz是一个很著名的开源作业调度器,可以创建大量job,按照丰富的自定义日历表进行调度执行。
官网:http://www.quartz-scheduler.org
本文首先介绍一下quartz的使用,然后分享一个自己在使用的过程中遇到的小陷阱——job的状态问题
quartz的使用:
quartz的介绍和使用网上有很多,可以参考一下这篇文章:
http://www.blogjava.net/hao446tian/archive/2011/05/24/350901.html
quartz主要有几个基本概念:
Job : 一个接口,我们的任务实现该接口、调度器来按时执行我们的任务
public interface Job {
public void execute(JobExecutionContext context) throws JobExecutionException;
}
JobDetail:描述Job实现类的信息
Trigger:触发器,有两种(简单触发器SimpleTrigger、时间表达式触发器CronTrigger )
Scheduler:调度器,调度各个job按时按此执行
一个简单例子:
public class CronTriggerRunner {
public static void main(String args[]) {
try {
// 定义了一个job:SimpleJob,其实现了Job接口
JobDetail jobDetail = new JobDetail("job1_2", "jGroup1",SimpleJob.class);
// 定义了相应的时间触发器
CronTrigger cronTrigger = new CronTrigger("trigger1_2", "tgroup1");
// 设置时间触发条件表达式:每5秒执行一次
CronExpression cexp = new CronExpression("0/5 * * * * ?");
cronTrigger.setCronExpression(cexp);
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// 关联job和其触发器
scheduler.scheduleJob(jobDetail, cronTrigger);
// 启动调度器
scheduler.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
自己遇到的一个陷阱:
quartz调度器在进行job调度的时候,每次都会创建该job实现类的一个实例,如果每个实例之间共享一些状态,则就会出现问题,如:若job实现类定义了一个static变量,则该static变量就会被每次创建的实例所共享,如果前一次创建的实例修改了这个static变量,则在下一次调度该job,创建其实例时,会看到这个改变,所以要特别注意这点。
举例说明:
public class ScpLogJob implements Job {
private static final int SCP_THREAD_NUM = 4;
private static ExecutorService exe = Executors
.newFixedThreadPool(SCP_THREAD_NUM);
try {
exe.execute(task);
}
} finally {
try {
exe.shutdown();
} catch (Exception e) {
}
}
}
这个job里有一个static的线程执行期exe,在这个job第一次被调度执行的时候,创建该job的实例,即创建了exe,但下一次调度执行该job的时候,又要创建该job的实例,但exe是同一个,而exe在job第一次执行结束后关闭了,所以在第一次执行的时候exe是关闭的,我们的task就不能执行了。因此quartz每次都能按时调度我们的job去执行,但我们的job不能去真正干活了,因为exe在第一次执行后就被关闭了,所以自第一次之后我们的task就不能执行了。