1.Quartz介绍
Quartz是一个功能强大、灵活、使用简单的开源定时调度框架,支持单机、集群。
官网:http://www.quartz-scheduler.org/
2.Quartz使用
maven依赖,当前最新版本为2.3.2。
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
2.1.单机
2.1.1配置文件
创建名为quartz.properties的配置文件(配置文件非必须)。
配置:
#实例名
org.quartz.scheduler.instanceName = ddScheduler
#线程数
org.quartz.threadPool.threadCount = 3
#quartz相关数据放在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
配置详细介绍
主要配置:
- org.quartz.scheduler.instanceName:实例名,默认值QuartzScheduler。单实例时,没有什么意义,但使用集群功能时,功能相同的调度器应该使用相同的实例名。
- org.quartz.scheduler.instanceId:实例id,需要全局唯一,默认值NON_CLUSTERED。如果需要自动生成,则设为AUTO,如果需要从系统参数org.quartz.scheduler.instanceId中设置,则设为SYS_PROP。
- org.quartz.scheduler.instanceIdGenerator.class:只有org.quartz.scheduler.instanceId设置为AUTO时使用该参数,默认值是org.quartz.simpl.SimpleInstanceIdGenerator,基于主机名和时间戳生成instanceId。还有两个实现为SystemPropertyInstanceIdGenerator和HostnameInstanceIdGenerator,也可以自己实现生成器。
- org.quartz.scheduler.threadName:线程名,如果未指定,默认会使用org.quartz.scheduler.instanceName的值+_QuartzSchedulerThread作为线程名。
- org.quartz.scheduler.makeSchedulerThreadDaemon:指定调度器的线程是否为守护线程,值为true或false。
- org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer:quartz产生的线程是否继承初始化quartz实例的线程的context ClassLoader,值为true或false,设为true时,可以帮助类加载,JNDI查找等。(目前没搞明白具体有哪些影响,待后续研究)
- org.quartz.scheduler.idleWaitTime:调度器处于空闲的状态,调度器重新查询trigger前等待的时间,单位毫秒。通常不需要设置该参数。不建议使用小于5000ms的值,小于1000ms的值非法。
- org.quartz.scheduler.dbFailureRetryInterval:数据库断开重连的等待时间,单位毫秒。内存模式,此参数没有意义。
- org.quartz.scheduler.classLoadHelper.class:没搞懂有什么用,看官方文档说明,无需设置该参数,默认即可。
- org.quartz.scheduler.jobFactory.class:JobFactory使用的类,默认值为org.quartz.simpl.PropertySettingJobFactory,使用该工厂类的newInstance()来生成实例。
- org.quartz.context.key.SOME_KEY:替换scheduler context中的键值对,可以通过Scheduler.getContext()获取,org.quartz.context.key.MyKey = MyValue等价于scheduler.getContext().put("MyKey", "MyValue")。
- org.quartz.scheduler.userTransactionURL:将JNDI URL设置为quartz可以找到应用的事务管理器(UserTransaction manager),默认值java:comp / UserTransaction,只有使用JobStoreCMT且org.quartz.scheduler.wrapJobExecutionInUserTransaction=true时,才使用该选项。
- org.quartz.scheduler.wrapJobExecutionInUserTransaction:全局事务开关。设置为true,会在启动作业前开启事务,在作业完成时提交事务。设置为false,可以在类中使用@ExecuteInJTATransaction注解,为单个作业开启JTA(Java Transaction API)事务。
- org.quartz.scheduler.skipUpdateCheck:跳过quartz更新检查。true跳过更新检查,false不跳过,生产环境应该设置为false。
- org.quartz.scheduler.batchTriggerAcquisitionMaxCount:一个scheduler节点一次获取和触发的trigger的最大数量,默认值1。值越大,触发效率越高,但可能会造成负载不均衡。如果该值>1,且使用JDBC JobStore,则必须将org.quartz.jobStore.acquireTriggersWithinLock设为true,以免数据损坏。
- org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow:允许trigger在计划时间前被触发的时间,单位毫秒,默认值0。数字越大,触发器的批量采集越有可能选择并触发1个以上的触发器,代价是无法精确遵守触发时间表(触发器可能会提前触发此数量)。在有大量触发器同时或接近同时触发时,可以配置该参数,以提高性能。
线程池配置:
- org.quartz.threadPool.class:要使用的线程池实现类,默认值是空,quartz默认使用的线程池是org.quartz.simpl.SimpleThreadPool,基本能满足所有需求,无需更换。
- org.quartz.threadPool.threadCount:可以并发的线程数,默认值-1。当使用DefaultQuartzScheduler时,会读取quartz自带的properties文件,其中线程数为10。
- org.quartz.threadPool.threadPriority:线程优先级,最小值Thread.MIN_PRIORITY(1),最大值Thread.MAX_PRIORITY(10),默认值为Thread.NORM_PRIORITY(5)。
SimpleThreadPool特定的属性:
- org.quartz.threadPool.makeThreadsDaemons:设为true可以将线程池中的线程创建为守护线程,默认值是false。另外可以参见org.quartz.scheduler.makeSchedulerThreadDaemon属性。
- org.quartz.threadPool.threadsInheritGroupOfInitializingThread:继承分组的初始化线程,默认false。
- org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread:继承context ClassLoader的初始化线程,默认false。
- org.quartz.threadPool.threadNamePrefix:线程名前缀,会自动加上一个数字,默认值[Scheduler Name]_Worker。
RMI服务和客户端配置:略
2.1.2创建简单的小样例
该样例没有创建配置文件。
main code
try {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity("job1", "group1").build();
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1")
.startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever())
.build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
这里未使用schedule.shutdown(),因为一旦调用,整个调度器就会停止。实际使用时,quartz实例通常不会随意开关,实例的生命周期应该接近应用的生命周期,在应用启动后生成、启动quartz实例,在应用关闭前关闭quartz实例。
MyJob.java
public class MyJob implements Job {
private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
Date date = new Date();
String now = sdf.format(date);
System.out.println(String.format("[%s] i'm executing...", now));
}
}
此处有个坑,任务类MyJob必须是public class,否则会报以下错误: