这几天在做项目,需要用到定时器的功能,所以搜索了一下怎么写定时器,觉得quartz是一款简单易上手的,就是用了这个方式
首先必要的jar包必须要引入,
写一个TimedJob类去继承Job,重写里面的唯一的方法execute,就是你需要定时工作的内容,
如果需要传参,可以使用的方式:
(1)JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String time = jobDataMap.getString("time");
(2) private String orderId;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
这两种方式都可以获取需要传的参数;
import java.util.Date;
import net.sf.json.JSONObject;
import org.hamcrest.core.IsNot;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class TimedJob implements Job{
/*
* 需要被执行的定时任务类
* */
private String orderId;//
private String msg;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("定时器工作");
/*JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
String time = jobDataMap.getString("time");*/
System.out.println("orderid:"+orderId+new Date());
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
然后写一个TimeManager管理配置这个定时工作的任务
import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
public class TimeManager {
/*
* 配置需要执行的方法类
* */
public void go(String orderId) throws Exception {
// 首先,必需要取得一个Scheduler的引用
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
//jobs可以在scheduled的sched.start()方法前被调用
//job 1将每2分钟执行一次(在该分钟的第15秒)
JobDetail job = newJob(TimedJob.class).withIdentity("job1", "group1").usingJobData("orderId", orderId).build();
CronTrigger trigger = newTrigger().withIdentity("trigger1", "group1").withSchedule(cronSchedule("15 0/1 * * * ?")).build();
Date ft = sched.scheduleJob(job, trigger);
//System.out.println(job.getKey() + " 已被安排执行于: " + sdf.format(ft) + ",并且以如下重复规则重复执行: " +
// 开始执行,start()方法被调用后,计时器就开始工作,计时调度中允许放入N个Job
sched.start();
try {
//主线程等待一分钟
Thread.sleep(60L * 1000L);
} catch (Exception e) {}
//关闭定时调度,定时器不再工作
sched.shutdown(true);
}
}
这个定时器写好后我的模块确实可以正常工作了,但是同时也需要使用我的方法的时候发现调用定时器出问题,不能同时调用两个定时器,
我就在想我的定时器是不是并行任务,于是了解到未做处理的quartz定时器默认就是并行的,所以一时间没有找到究竟错在了哪里
后来请教了一下老员工,
JobDetail job = newJob(TimedJob.class).withIdentity("job1", "group1").usingJobData("orderId", orderId).build();
因为我作为识别的定时器任务配置的都是job1,trigger1,所以在复用的情况下再次调用的时候其实我的job1和trigger1已经开启了,所以无法调用,
这个时候为了提高代码的复用,和定时器的使用,所以就将job1和trigger1改成了不重复自动生成的哈希值代替就解决了定时器复用的问题
又在老员工的帮助下写了一个新的简单的方法,新写一个urtil类
public static void startJob(String jobName, String triggerName, String groupName, Class jobCLass, Date jobStartTime, Integer intervalHours, int repeatCount, Map<String, Object> params) throws SchedulerException {
Scheduler scheduler = sf.getScheduler();
JobBuilder jobBuilder = JobBuilder.newJob(jobCLass);
if(params != null) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
if(entry.getValue() instanceof Boolean) {
jobBuilder.usingJobData(entry.getKey(), (Boolean) entry.getValue());
} else if(entry.getValue() instanceof Integer) {
jobBuilder.usingJobData(entry.getKey(), (Integer) entry.getValue());
} else if(entry.getValue() instanceof Float) {
jobBuilder.usingJobData(entry.getKey(), (Float) entry.getValue());
} else if(entry.getValue() instanceof Long) {
jobBuilder.usingJobData(entry.getKey(), (Long) entry.getValue());
} else if(entry.getValue() instanceof Double) {
jobBuilder.usingJobData(entry.getKey(), (Double) entry.getValue());
} else {
jobBuilder.usingJobData(entry.getKey(), entry.getValue().toString());
}
}
}
if (StringUtils.isNotEmpty(jobName) && StringUtils.isNotEmpty(groupName)) {
jobBuilder.withIdentity(jobName, groupName);
}
JobDetail jobDetail = jobBuilder.build();
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
if (StringUtils.isNotEmpty(triggerName) && StringUtils.isNotEmpty(groupName)) {
triggerBuilder.withIdentity(triggerName, groupName);
}
if (jobStartTime == null) {
triggerBuilder.startNow();
} else {
triggerBuilder.startAt(jobStartTime);
}
Trigger trigger = triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInHours(intervalHours).withRepeatCount(repeatCount)).build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
一起解决了传值问题和配置问题,使用起来更加方便了
然后我就将我的TimeManager类中的go方法吧之前的都删了就换成了下面这句
QuartzManageUtils.startJob(DateUtil.getCurrentTimeZone(), DateUtil.getCurrentTimeZone(), "group1", TimedJob.class, DateUtil.addDay(new Date(), 0), 1, 1, params);
完全可以复用quartz定时器