我们已经实施了石英调度。每个生产的工作都有不同的关键。到目前为止工作正常。昨天我们遇到了一个问题,因为两个不同的Quartz-Worker线程正在执行两次或三次相同的工作(没有特定的行为)。 我们不能使线程池大小为1,因为我们需要并发作业。
关于我们预定工作的一个值得注意的事情是,它在每次运行时重新安排(每天,每周或每月),即如果一项工作计划每天运行,那么它将在接下来的24小时内重新安排,但随机预定义(比如说) 3小时)时间窗口。例如,如果一份工作今天在4:10(即4:00到7:00)之间运行,那么我们的工作将在4:00到7:00之间的某个随机时间自行重新安排到明天。它可能是4:01或6:59或5:23或给定时间窗口中的任何其他值。这个过程也运行良好,大多数情况下仍然可以正常工作,除非在某些情况下我们的重新调度算法未能在接下来的24小时内安排好。相反,它会在接下来的10秒,1小时或任何其他随机值中安排自己。但它最终在2-3次错误的重新安排之后稳定了自己,即它最终在接下来的24小时内安排好了。我们怀疑这可能是由于多个线程访问Calendar对象(我们使用Calendar.getInstance()和cal.add(Calendar.DAY_OF_YEAR,1)在接下来的24小时内重新安排作业)。不知何故,日历实例选择了错误的时间,或者无法在当前时间添加一天。
所以,有两个问题: 1.多个Quartz线程获得相同的工作 2.在某些特定情况下(多线程访问),日历无法添加给定间隔或选择错误的当前时间
任何帮助将不胜感激。尽快回复。 感谢。
感谢您的回复。 我想知道Statefuljob和@DisallowConcurrentExecution注释之间的区别是什么,并将threadPool.threadCount设置为1.
重新安排的代码是......
Calendar cal = Calendar.getInstance();
Calendar nextCal = Calendar.getInstance();
cal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone()));
nextCal.setTimeZone(TimeZone.getTimeZone(obj.getTimeZone()));
Date startTime = null;
SimpleTrigger trigger = null;
JobDataMap dataMap = new JobDataMap();
if (repeatTimeInMillis == null) {
cal.set(Calendar.HOUR_OF_DAY, obj.getStartTime());
nextCal.set(Calendar.HOUR_OF_DAY, obj.getStartTime());
cal.set(Calendar.MINUTE, 0);
nextCal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
nextCal.set(Calendar.SECOND, 0);
if (obj.getScheduleType() == ScheduleType.MONTHLY) { // Monthly
log.info("in monthly schedule");
nextCal.add(Calendar.MONTH, 2);
nextCal.set(Calendar.DAY_OF_MONTH, obj.getDate());
cal.add(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, obj.getDate());
} else if (obj.getScheduleType() == ScheduleType.WEEKLY) { // Weekly
log.info("in weekly schedule");
nextCal.add(Calendar.WEEK_OF_YEAR, 2);
nextCal.set(Calendar.DAY_OF_WEEK, obj.getDay());
cal.add(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, obj.getDay());
} else if (obj.getScheduleType() == ScheduleType.DAILY) { // Daily
log.info("in daily schedule");
nextCal.add(Calendar.DAY_OF_YEAR, 2);
cal.add(Calendar.DAY_OF_YEAR, 1);
}
long time = obj.getTimeWindow() * 60 * 60 * 1000;
time = Math.round(time * Math.random());
cal.setTimeInMillis(cal.getTimeInMillis() + time);
startTime = cal.getTime();
nextCal.setTimeInMillis(nextCal.getTimeInMillis() + time);
repeatTimeInMillis = nextCal.getTimeInMillis() - cal.getTimeInMillis();
log.info("Rescheduling job at " + startTime);
trigger = newTrigger().usingJobData(dataMap)
.withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).repeatForever())
.build();
} else {
log.info("Rescheduling job next " + repeatTimeInMillis + " milliseconds.");
cal.setTimeInMillis(cal.getTimeInMillis() + repeatTimeInMillis);
startTime = cal.getTime();
trigger = newTrigger().usingJobData(dataMap)
.withIdentity(obj.getScheduleJobName(), obj.getScheduleJobGroup()).startAt(startTime)
.withSchedule(simpleSchedule().withIntervalInMilliseconds(repeatTimeInMillis).withRepeatCount(1)).build();
}
答案 0 :(得分:3)
StatefulJob接口和@DisallowConcurrentExecution注释做同样的事情。
来自DisallowConcurrentExecution javadoc:
将Job类标记为不能有多个实例的Job类 同时执行....
这可以用来代替实现StatefulJob标记 在Quartz 2.0之前使用的接口
将threadPool.threadCount属性设置为1意味着最多可以执行任何的作业
使用这些解决方案中的任何一个都将停止并发执行的作业,并导致任何触发器被放入队列中,以便在上一个触发器实例完成时执行