Java 定时任务quartz
quartz定时任务
一、添加Maven依赖
<!-- 定时任务 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
二、创建执行任务的任务类
如下所示:创建了TestJob01并实现了Job,该任务只是简单的打印当前时间
package cn.wh.job; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; /** * 定时执行任务的任务类-测试 * @author wanghao * */ public class TestJob01 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); System.out.println("任务打印"+sdf.format(new Date())); } }
三、创建调用任务的调度类
package cn.wh.scheduler; import cn.wh.job.TestJob01; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; /** * 任务调度类 */ public class TestJob01Scheduler { //创建调度器 public static Scheduler getScheduler() throws SchedulerException { SchedulerFactory schedulerFactory = new StdSchedulerFactory(); return schedulerFactory.getScheduler(); } // 执行任务 public static void run() throws SchedulerException{ //创建任务 JobDetail jobDetail = JobBuilder.newJob(TestJob01.class).withIdentity("testJob01", "group11").build(); //创建触发器 每5秒钟执行一次 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group21") .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever()) .build(); Scheduler scheduler = getScheduler(); //将任务及其触发器放入调度器 scheduler.scheduleJob(jobDetail, trigger); //调度器开始调度任务 // 启动 if (!scheduler.isShutdown()) { scheduler.start(); } } public static void main(String[] args) throws SchedulerException { TestJob01Scheduler testJob01Scheduler = new TestJob01Scheduler(); testJob01Scheduler.run(); } }
执行结果如下图所示:每隔五秒执行一次

执行过程如下图:

使用Cron表达式,执行定时任务
Cron表达式包含6个必要组件和一个可选组件,如下表所示。
|
位置 |
含义 |
允许的特殊字符 |
|
1 |
秒(0~59) |
, - * / |
|
2 |
分(0~59) |
, - * / |
|
3 |
小时(0~24) |
, - * / |
|
4 |
日期(1~31) |
, - * / ? L W C |
|
5 |
月(JAN~DEC或1~12) |
, - * / |
|
6 |
星期(SUN~SAT或1~7) |
, - * / ? L C # |
|
7 |
年(可选,1970~2099),若为空,表示全部时间范围 |
, - * / |
|
特殊字符 |
说明 |
|
* |
通配符,任意值 |
|
? |
无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查 |
|
- |
范围。e.g.小时部分10-12表示10:00,11:00, 12:00 |
|
, |
列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED |
|
/ |
增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min |
|
L |
表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五 |
|
W |
在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。 |
|
# |
表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一 |
|
C |
日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五) |
代码如下:
package cn.wh.utils; import cn.wh.job.TestJob01; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; public class QuartzManager { private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory(); private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME"; private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME"; /** * 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名 * @param jobName 任务名 * @param cls 任务 * @param time 时间设置 */ public static void addJob(String jobName, Class cls, String time) { try { // org.quartz-scheduler Scheduler sched = gSchedulerFactory.getScheduler(); // 任务名,任务组,任务执行类 //创建任务 JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, TRIGGER_GROUP_NAME).build(); //可以传递参数 jobDetail.getJobDataMap().put("param", "railsboy"); // 触发器 //每秒钟触发一次任务 CronTrigger trigger = TriggerBuilder.newTrigger(). withIdentity(jobName, TRIGGER_GROUP_NAME). withSchedule(CronScheduleBuilder.cronSchedule("*/3 * * * * ? *")). build(); // 触发器时间设定 sched.scheduleJob(jobDetail, trigger); // 启动 if (!sched.isShutdown()) { sched.start(); } } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { QuartzManager.addJob("Test01",TestJob01.class,""); } }
可以看到任务每三秒执行一次。

五、实现动态定时任务
5.1 定时任务管理类
定时任务管理类包含调度器初始化、新增/更新任务、停止任务、执行一次任务
5.1.1 调度器初始化
默认调度器线程10个
public class QuartzDynamicTaskManager {
public static final String JOB_KEYNAME_PREFIX = "JOB_"; public static final String TRIGGER_KEYNAME_PREFIX = "TRIGGER_"; public static final String JOB_COMMON_GROUP = "DEFAULT_GROUP"; // Quartz调度器 private final Scheduler scheduler; public QuartzDynamicTaskManager() throws SchedulerException { // 初始化调度器 StdSchedulerFactory factory = new StdSchedulerFactory(); this.scheduler = factory.getScheduler(); // 获取元数据,查看线程池大小 int threadPoolSize = scheduler.getMetaData().getThreadPoolSize(); log.info("Quartz默认线程池默认大小:{}",threadPoolSize); scheduler.start(); } }
5.1.2 新增/更新任务/恢复任务
新增任务和更新任务可以分开也可以合到一个方法如下:
使用了泛型进行通用的定时任务管理
/** * 新增/更新定时任务 * @param taskId 任务ID(作为JobKey和TriggerKey的标识) * @param jobGroup 任务组 * @param cron Cron表达式 * @param param 任务参数 * @throws SchedulerException * @throws ParseException */ public void addOrUpdateTask(String taskId,String jobGroup, String cron, String param,Class<? extends Job> clz) throws SchedulerException, ParseException { JobKey jobKey = new JobKey(taskId, jobGroup); TriggerKey triggerKey = new TriggerKey(TRIGGER_KEYNAME_PREFIX+ taskId, jobGroup); JobDetail jobDetail = scheduler.getJobDetail(jobKey); if (jobDetail == null) { jobDetail = JobBuilder.newJob(clz) .withIdentity(jobKey) .usingJobData("param", param) // 设置任务参数 .storeDurably(true) // 即使没有触发器也保留任务 .build(); scheduler.addJob(jobDetail, true); } else { jobDetail.getJobDataMap().put("param", param); scheduler.addJob(jobDetail, true, true); // 覆盖更新 } Trigger oldTrigger = scheduler.getTrigger(triggerKey); if (oldTrigger != null) { scheduler.unscheduleJob(triggerKey); } CronTriggerImpl newTrigger = new CronTriggerImpl(); newTrigger.setKey(triggerKey); newTrigger.setCronExpression(cron); newTrigger.setJobKey(jobKey); scheduler.scheduleJob(newTrigger); log.info("Quartz任务,taskId:{}新增/更新成功,新的Cron:{}",taskId,cron); }
5.1.3 停止任务
停止任务相当于把任务移除,包括触发器移除,所以恢复任务可以调用任务添加
/** * 停止任务 * @param taskId 任务key * @param jobGroup 任务组 * @throws SchedulerException */ public void stopTask(String taskId,String jobGroup) throws SchedulerException { TriggerKey triggerKey = new TriggerKey(TRIGGER_KEYNAME_PREFIX + taskId, jobGroup); scheduler.unscheduleJob(triggerKey); JobKey jobKey = new JobKey(taskId, jobGroup); scheduler.deleteJob(jobKey); log.info("Quartz任务,taskId:{}已停止",taskId); }
5.1.4 执行一次
普通的执行一次方法,参数使用的是初始化任务的默认参数
public void triggerJobOnce(String taskId,String jobGroup) throws SchedulerException { // 根据任务ID构建JobKey(和创建任务时的JobKey保持一致!) JobKey jobKey = new JobKey(taskId, jobGroup); // 校验任务是否存在 if (!scheduler.checkExists(jobKey)) { throw new IllegalArgumentException("任务ID【"+taskId+"】不存在,无法手动触发!"); } // 核心API:手动触发,立即执行一次 scheduler.triggerJob(jobKey); System.out.println("任务["+taskId+"]手动触发成功,已立即执行一次!"); }
传入新的参数执行一次方法
public void triggerJobOnce(String jobId,String jobGroup, Map<String, Object> paramMap) throws SchedulerException { JobKey jobKey = new JobKey(jobId, jobGroup); if (!scheduler.checkExists(jobKey)) { throw new IllegalArgumentException("任务ID【"+jobId+"】不存在,无法手动触发!"); } // 构建临时参数Map,本次执行生效,不影响原任务 JobDataMap jobDataMap = new JobDataMap(paramMap); // 核心API:手动触发+传参 scheduler.triggerJob(jobKey, jobDataMap); System.out.println("任务["+jobId+"]手动触发成功,带参执行一次!"); }
job每次执行都创建新的实例

浙公网安备 33010602011771号