我有一个每个间隔运行的作业(对于下面的例子,3秒),有时可能需要超过间隔,在这种情况下,我希望它立即开始一项新工作并保持定期延迟(3秒)并且不会运行所有失误的工作。
在下面的示例中,我启动了一个每3秒执行一次作业的调度程序
第四份工作将睡15秒 这意味着5个工作岗位将被熄火并且在石英队列中
有一种奇怪的行为,我会尽力解释;
如果我使用默认配置启动StdSchedulerFactory,它将运行所有失效的作业 但如果我启动它并将“org.quartz.threadPool.threadCount”属性设置为数字> 0它不会全部失效(按要求工作),为什么会这样?
import org.quartz.DisallowConcurrentExecution;
import org.quartz.CronScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
/**
* synchronized job scheduler test;
* if job execution time took more than the interval then:
* - start new job right away
* - do not run misfired jobs
* - keep regular delay afterwards
*/
public class Main {
private static final String CRON_EXPRESSION = "0/2 * * * * ?";
private static final String GROUP_KEY = "group1";
private static final String JOB_KEY = "job1";
private static final String TRIGGER_KEY = "trigger1";
// for logging purposes only
private static AtomicInteger jobsCounter = new AtomicInteger(0);
private static final String LOG_DATE_TIME_FORMAT = "HH:mm:ss";
private static final DateFormat DF = new SimpleDateFormat(LOG_DATE_TIME_FORMAT);
public static void main(String[] args) {
JobKey jobKey = new JobKey(JOB_KEY, GROUP_KEY);
JobDetail job = JobBuilder.newJob(CustomJob.class).withIdentity(jobKey).build();
/*
misfired job means job threw JobExecutionException
in our case the job finish after the interval so none of this flags aren't helpful
cronSchedule.withMisfireHandlingInstructionFireAndProceed()
.withMisfireHandlingInstructionIgnoreMisfires()
.withMisfireHandlingInstructionDoNothing()
*/
CronScheduleBuilder cronSchedule = CronScheduleBuilder.cronSchedule(CRON_EXPRESSION);
TriggerKey triggerKey = new TriggerKey(TRIGGER_KEY, GROUP_KEY);
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronSchedule).build();
try {
Properties props = new Properties();
// default configuration
props.put("org.quartz.threadPool.threadCount", "10");
props.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", "true");
props.put("org.quartz.scheduler.rmi.proxy", "false");
props.put("org.quartz.scheduler.instanceName", "DefaultQuartzScheduler");
props.put("org.quartz.scheduler.wrapJobExecutionInUserTransaction", "false");
props.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
props.put("org.quartz.jobStore.class", "org.quartz.simpl.RAMJobStore");
props.put("org.quartz.threadPool.threadPriority", "5");
/**
org.quartz.jobStore.misfireThreshold
The the number of milliseconds the scheduler will ‘tolerate’ a trigger to pass its next-fire-time by,
before being considered “misfired”.
The default value (if you don’t make an entry of this property in your configuration) is 60000 (60 seconds).
*/
// FIXME UNDERSTAND STRANGE BEHAVIOR
// props.put("org.quartz.jobStore.misfireThreshold", "9100"); // this will execute all the jobs in queue when job wake up
props.put("org.quartz.jobStore.misfireThreshold", "8900"); // this will execute once and continue as requested
/**
* strange behavior HERE if we initiate StdSchedulerFactory with default c'tor
* Scheduler scheduler = new StdSchedulerFactory().getScheduler();
*/
Scheduler scheduler = new StdSchedulerFactory(props).getScheduler();
// Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
}
catch (SchedulerException e) {
System.err.println(e.getMessage());
}
}
@DisallowConcurrentExecution // based upon JobKey
public static class CustomJob implements Job { // must be public for quartz to start
int jid; // job id, incremental
public CustomJob() {
jid = jobsCounter.incrementAndGet();
log("c'tor");
}
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
log("start");
// sleep for 15 seconds at job #4
if (jid == 4) {
log("* sleep *");
Thread.sleep(11 * 1_000);
}
log("end");
} catch (InterruptedException ignored) {}
}
private void log(String s) {
String curTime = DF.format(new Date());
StringBuffer sb = new StringBuffer().append(curTime).append("\t#").append(jid).append("\t").append(s);
System.out.println(sb);
}
}
}