Some quartz records and quartz records
Scheduled tasks always run in the case of overlapping tasks. For example, if a task is executed once every minute and the task execution time exceeds one minute, two identical tasks are executed concurrently. Sometimes we allow this situation to happen. For example, the Code executed by a task is idempotent, and sometimes we may consider that it is not allowed to happen in some cases.
In actual scenarios, we use quartz to schedule scheduled tasks. The Business Code of scheduled tasks is distributed in various applications and called using soa.
For quartz, the official document clearly specifies a solution to this requirement, that is, using annotation @ DisallowConcurrentExecution;
Meaning: Prohibit concurrent execution of multiple JobDetail with the same definition, which is what we want.
The following example compares two jobs: AllowConcurrentExecutionTestJob and DisallowConcurrentExecutionTestJob.
Public class AllowConcurrentExecutionTestJob implements Job {public AllowConcurrentExecutionTestJob () {} public void execute (JobExecutionContext context) throws JobExecutionException {try {List <JobExecutionContext> list = context. getScheduler (). getCurrentlyExecutingJobs (); for (JobExecutionContext jobExecutionContext: list) {// get the variable System in the container in the job. out. println (jobExecutionContext. getJobDetail (). GetKey (). getName ();} Thread. sleep (4000);} catch (SchedulerException e) {e. printStackTrace ();} catch (InterruptedException e) {e. printStackTrace ();} System. out. println ("Hello World! AllowConcurrentExecutionTestJob is executing .");}}
@ DisallowConcurrentExecutionpublic class DisallowConcurrentExecutionTestJob implements org. quartz. job {public DisallowConcurrentExecutionTestJob () {} public void execute (JobExecutionContext context) throws JobExecutionException {try {List <JobExecutionContext> list = context. getScheduler (). getCurrentlyExecutingJobs (); for (JobExecutionContext jobExecutionContext: list) {// get the variable System in the container in the job. ou T. println (jobExecutionContext. getJobDetail (). getKey (). getName ();} Thread. sleep (4000);} catch (SchedulerException e) {e. printStackTrace ();} catch (InterruptedException e) {e. printStackTrace ();} System. out. println ("Hello World! DisallowConcurrentExecutionTestJob is executing .");}}
Test code:
public class QuartzTest { public static void main(String[] args) throws InterruptedException { try { // Grab the Scheduler instance from the Factory Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // and start it off scheduler.start(); // define the job and tie it to our HelloJob class JobDetail job = JobBuilder.newJob(DisallowConcurrentExecutionTestJob.class) .withIdentity("job1", "group1") .build(); // Trigger the job to run now, and then repeat every 40 seconds Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) .repeatForever()) .build(); // define the job and tie it to our HelloJob class JobDetail job2 = JobBuilder.newJob(AllowConcurrentExecutionTestJob.class) .withIdentity("job2", "group1") .build(); // Trigger the job to run now, and then repeat every 40 seconds Trigger trigger2 = TriggerBuilder.newTrigger() .withIdentity("trigger2", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) .repeatForever()) .build(); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job2, trigger2);// scheduler.scheduleJob(job2, trigger2); // wait trigger Thread.sleep(20000); scheduler.shutdown(); } catch (SchedulerException se) { se.printStackTrace(); } }}
We also found that the parameter JobExecutionContext is passed in the execute of the job, which allows us to get information about the job being executed. So I want to know whether there are the same jobs that are already being executed in the job.
public class SelfDisAllowConExeTestJob implements org.quartz.Job{ public void execute(JobExecutionContext context) throws JobExecutionException { try { List<JobExecutionContext> list = context.getScheduler().getCurrentlyExecutingJobs(); Set<String> jobs = new HashSet<String>(); int i=0; for (JobExecutionContext jobExecutionContext : list){ if(context.getJobDetail().getKey().getName().equals(jobExecutionContext.getJobDetail().getKey().getName())){ i++; } } if(i>1){ System.out.printf("self disallow "); return; } Thread.sleep(4000); } catch (SchedulerException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Hello World! SelfDisAllowConExeTestJob is executing."); }}
Test code:
public class OuartzSelfMapTest { public static void main(String[] args) throws InterruptedException { try { // Grab the Scheduler instance from the Factory Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // and start it off scheduler.start(); // define the job and tie it to our HelloJob class JobDetail job = JobBuilder.newJob(SelfDisAllowConExeTestJob.class) .withIdentity("job1", "group1") .build(); // Trigger the job to run now, and then repeat every 40 seconds Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1) .repeatForever()) .build(); // Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job, trigger); // wait trigger Thread.sleep(20000); scheduler.shutdown(); } catch (SchedulerException se) { se.printStackTrace(); } }}
In actual code, we often combine spring to take a look at the concurrent attribute of MethodInvokingJobDetailFactoryBean to control whether concurrent execution is restricted:
Class<?> jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
/** * Extension of the MethodInvokingJob, implementing the StatefulJob interface. * Quartz checks whether or not jobs are stateful and if so, * won't let jobs interfere with each other. */ @PersistJobDataAfterExecution @DisallowConcurrentExecution public static class StatefulMethodInvokingJob extends MethodInvokingJob { // No implementation, just an addition of the tag interface StatefulJob // in order to allow stateful method invoking jobs. }
Of course, there is a StatefulJob in quartz, which facilitates direct inheritance and implements concurrent = false.
So I want to say that there is no interface in quartz that can be set to concurrent or not. Instead, it needs to be inherited by a custom job or implemented using annotations.
In addition, there is a related annotation: @ PersistJobDataAfterExecution
JobDataMap in JobDetail is shared, that is, information can be transmitted during execution of the same task. It is easy to think that since it is shared, there will be concurrency problems, as in the scenario described at the beginning, it will lead to concurrency problems. Therefore, the official documents also explain that this annotation is best used with @ DisallowConcurrentExecution.
The following is an example:
@PersistJobDataAfterExecutionpublic class PersistJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap data = context.getJobDetail().getJobDataMap(); int i = data.getInt("P"); System.out.printf("PersistJob=>"+i); i++; data.put("P", i); }}
Test code:
Public class PersistJobDataQuartzTest {public static void main (String [] args) throws InterruptedException {try {// Grab the Scheduler instance from the Factory Scheduler schedfactory = StdSchedulerFactory. getdefaschscheduler (); // and start it off scheduler. start (); JobDataMap jobDataMap = new JobDataMap (); jobDataMap. put ("P", 1); // define the job and tie it to our HelloJob class JobDetail job = JobBuilder. newJob (PersistJob. class ). withIdentity ("job1", "group1 "). usingJobData (jobDataMap ). build (); // Trigger the job to run now, and then repeat every 40 seconds Trigger trigger = TriggerBuilder. newTrigger (). withIdentity ("trigger1", "group1 "). startNow (). withSchedule (SimpleScheduleBuilder. simpleSchedule (). withIntervalInSeconds (1 ). repeatForever ()). build (); // Tell quartz to schedule the job using our trigger scheduler. scheduleJob (job, trigger); // wait trigger Thread. sleep (20000); scheduler. shutdown ();} catch (SchedulerException se) {se. printStackTrace ();}}}View Code
Reference:
Https://jayvilalta.com/blog/2014/06/04/understanding-the-disallowconcurrentexecution-job-attribute/http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-03http://www.cnblogs.com/lnlvinso/p/4194725.html