quartz.properties configuration: http://orange5458.iteye.com/blog/1170777
Quartz cluster scheduling mechanism research and source code analysis: http://www.cnblogs.com/davidwang456/p/4205237.html
In-depth interpretation of the principle of Quartz: http://lavasoft.blog.51cto.com/62575/181907/
quartz source code analysis: http://www.cnblogs .com/davidwang456/p/3878625.htmlQuartz
, an open source framework for task scheduling, dynamically adds, modifies and deletes timed tasks: http://www.tuicool.com/articles/Ff6F7v
New JOb
package job; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.JobKey; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SimpleJob implements Job { private static int jobCount = 0; Logger log = LoggerFactory.getLogger(SimpleJob.class); @Override public void execute(JobExecutionContext context) throws JobExecutionException { // This task only prints logs for debugging and observation log.info("==================:"+this.getClass().getName() + " was just triggered..."); JobKey jobKey = context.getJobDetail().getKey(); TriggerKey triggerKey = context.getTrigger().getKey(); Scheduler scheduler = context.getScheduler(); //Start the thread to monitor the state of the trigger new Thread(new SchedEventLister(triggerKey,scheduler)).start(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); log.info("Task group name: " + jobKey.getGroup()+", task name: " + jobKey.getName()+", trigger group name: " + triggerKey.getGroup()+ ", trigger name: "+ triggerKey.getName()+" execution time: " + sdf.format(new Date()) + ", count: " + (++jobCount)) ; //End the task if it executes more than 15 times /* if(jobCount > 3){ log.warn("End task..."); try { //Delete the identified Job from the Scheduler - and any associated Triggers. //Deleting this unique task from the scheduler will also delete the associated trigger ^_^ scheduler.deleteJob(jobKey); } catch (SchedulerException e) { e.printStackTrace (); } }*/ if(jobCount == 2 ){ //pause trigger try { scheduler.pauseTrigger (triggerKey); log.warn("The trigger has been paused..., trigger group name: " + triggerKey.getGroup() + ", trigger name: " + triggerKey.getName()); } catch (SchedulerException e) { throw new RuntimeException(e); } } if(jobCount == 4){ try { scheduler.pauseTrigger(triggerKey); // stop trigger scheduler.unscheduleJob(triggerKey);//Remove trigger scheduler.pauseJob(jobKey);// stop the task scheduler.deleteJob(jobKey);// delete task log.error("Stopping and removing trigger..., trigger group name: " + triggerKey.getGroup() + ", trigger name: " + triggerKey.getName()); } catch (SchedulerException e) { throw new RuntimeException(e); } } } }
Job listener:
package job; import java.text.SimpleDateFormat; import java.util.Date; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import org.quartz.TriggerKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SchedEventLister implements Runnable{ private static Logger log = LoggerFactory.getLogger(SchedEventLister.class); private Scheduler sched = null; private TriggerKey triggerKey = null; public SchedEventLister(TriggerKey triggerKey,Scheduler sched) { log.info("Trigger thread monitor start...."); this.triggerKey = triggerKey; this.sched = sched; } @Override public void run() { log.info("Trigger thread listening..." + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") .format(new Date())); // Get the state of the current trigger Trigger.TriggerState ts = null; try { ts = sched.getTriggerState(triggerKey); } catch (SchedulerException e) { e.printStackTrace (); } // resume if paused if (ts == Trigger.TriggerState.PAUSED) { // Pause for 10 seconds before resuming try { log.warn("Resume trigger after suspending the current thread for 5 seconds..., trigger group name: " + triggerKey.getGroup() + ", trigger name: " + triggerKey.getName()); Thread.sleep(5L * 1000L); } catch (InterruptedException e1) { e1.printStackTrace(); } // restore trigger log.warn("Restoring trigger..., trigger group name: " + triggerKey.getGroup() + ", trigger name: " + triggerKey.getName()); try { sched.resumeTrigger(triggerKey); } catch (SchedulerException e) { throw new RuntimeException(e); } } else if (ts == Trigger.TriggerState.NORMAL) { log.info("Trigger thread listening..., status: normal"); } else if (ts == Trigger.TriggerState.NONE) { log.info("Trigger thread listening..., status: no trigger"); } else if (ts == Trigger.TriggerState.ERROR) { log.info("Trigger thread listening..., status: error"); } else if (ts == Trigger.TriggerState.BLOCKED) { log.info("Trigger thread listening..., status: blocked"); } } }
Simple trigger test:
package job; import java.util.concurrent.TimeUnit; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class testSimpleTrriger { private static Logger logger = LoggerFactory.getLogger (testSimpleTrriger.class); public static void main(String[] args) { try { // Get Scheduler instance Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // specific task JobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity("SimpleJob", "Job-Group-Simple").build(); // trigger time SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever(); Trigger trigger = TriggerBuilder.newTrigger().withIdentity("SimpleTrigger", "Trriger-Group-Simple"). startNow().withSchedule(simpleScheduleBuilder).build(); // hand over to Scheduler to arrange trigger scheduler.scheduleJob(job, trigger); scheduler.start(); try { TimeUnit.MINUTES.sleep(2); } catch (InterruptedException e) { e.printStackTrace (); } // close Scheduler scheduler.shutdown(); } catch (SchedulerException se) { logger.error(se.getMessage(), se); } } }
CronTrigger trigger test:
package job; import java.util.concurrent.TimeUnit; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestCronTrriger { private static Logger logger = LoggerFactory.getLogger (testSimpleTrriger.class); public static void main(String[] args) { try { // Get Scheduler instance SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler cronScheduler = schedulerFactory.getScheduler(); // specific task JobDetail job = JobBuilder.newJob(SimpleJob.class).withIdentity("SimpleJob", "Job-Group-Simple").build(); // trigger time // hand over to Scheduler to arrange trigger String cronExpression = "0/5 * * * * ?"; // From 30s of every minute, the task is triggered every 5s CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("SimpleTrigger", "Trriger-Group-Simple") .withSchedule(cronScheduleBuilder) .build(); cronScheduler.scheduleJob(job, cronTrigger); cronScheduler.start(); try { /* In order to observe the running of the program, the main program sleeps for 2 minutes before continuing to run (because the next step is to "close the Scheduler") */ TimeUnit.MINUTES.sleep(2); } catch (InterruptedException e) { e.printStackTrace (); } // close Scheduler cronScheduler.shutdown(); } catch (SchedulerException se) { logger.error(se.getMessage(), se); } } }
The above two test classes are just different types of test triggers, and the jobs that are processed hard are the same
Test results:
September 05, 2016 9:41:00 am org.quartz.impl.StdSchedulerFactory instantiate
information: Using default implementation for ThreadExecutor
IX Sep 05, 2016 9:41:00 AM org.quartz.simpl. SimpleThreadPool initialize
info: Job execution threads will use class loader of thread: main
Sep 05, 2016 9:41:00 AM org.quartz.core.SchedulerSignalerImpl < init>
info: Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImplSeptember
05, 2016 9:41:00 AM org.quartz.core.QuartzScheduler <init>
info: Quartz Scheduler v.2.2.1 created.
September 05, 2016 9:41:00 am org.quartz.simpl.RAMJobStore initialize
信息: RAMJobStore initialized.
九月 05, 2016 9:41:00 上午 org.quartz.core.QuartzScheduler initialize
信息: Scheduler meta-data: Quartz Scheduler (v2.2.1) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
九月 05, 2016 9:41:00 上午 org.quartz.impl.StdSchedulerFactory instantiate
信息: Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
###If quartz.properties is configured, load relevant configuration information from quartz.properties file
September 05, 2016 9:41:00 am org.quartz.impl. StdSchedulerFactory instantiate
information: Quartz scheduler version:
2.2.1September 05, 2016 9:41:00 am org.quartz.core.QuartzScheduler start
information: Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started. #First
executionSeptember
05, 2016 9: 41:00 AM job.SimpleJob execute
info: ===================: job.SimpleJob was just triggered...
September 05, 2016 9:41:00 AM job .SchedEventLister <init>
info: Trigger thread listening started....
September 05, 2016 9:41:00 AM job.SchedEventLister run
info: Trigger thread listening. . . . 2016-09-05 09:41:00
Sep 05, 2016 9:41:00 AM job.SimpleJob execute
info: Job Group Name: Job-Group-Simple, Job Name: SimpleJob, Trigger Group Name: Trriger-Group-Simple, Trigger Name: SimpleTrigger Execution Time : 2016-09-05 09:41:00, count: 1
Sep 05, 2016 9:41:00 AM job.SchedEventLister run
info: Trigger thread listening. . . . , status: normal
# Second execution, pause for 5 seconds, then resume
September 05, 2016 9:41:05 AM job.SimpleJob execute
information: ================ ==:job.SimpleJob was just triggered...
Sept 05, 2016 9:41:05 AM job.SchedEventLister <init>
INFO: Trigger thread listener started....
Sep 05, 2016 9:41:05 Morning job.SimpleJob execute
information: Task group name: Job-Group-Simple, task name: SimpleJob, trigger group name: Trriger-Group-Simple, trigger name: SimpleTrigger Execution time: 2016-09-05 09:41: 05, count: 2
Sep 05, 2016 9:41:05 am job.SchedEventLister run
INFO: Trigger thread listening. . . . 2016-09-05 09:41:05
Sep 05, 2016 9:41:05 AM job.SimpleJob execute
Warning: Trigger already paused..., Trigger Group Name: Trriger-Group-Simple, Trigger Name : SimpleTrigger
Sep 05, 2016 9:41:05 AM job.SchedEventLister run
Warning: Resume trigger after suspending current thread for 5 seconds..., trigger group name: Trriger-Group-Simple, trigger name: SimpleTrigger
Sep 05, 2016 9:41:10 AM job.SchedEventLister run
Warning: Resuming triggers..., trigger group name: Trriger-Group-Simple, trigger name: SimpleTrigger
#3rd execution
Sep 05 , 2016 9:41:10 AM job.SimpleJob execute
info: ===================: job.SimpleJob was just triggered...
September 05, 2016 9:41 :10 AM job.SchedEventLister <init>
INFO: Trigger thread listener started....
September 05, 2016 9:41:10 AM job.SimpleJob execute
Info: Job Group Name: Job-Group-Simple, Job Name: SimpleJob, Trigger Group Name: Trriger-Group-Simple, Trigger Name: SimpleTrigger Execution Time: 2016-09-05 09:41:10, Count: 3
Sep 05, 2016 9:41:10 AM job.SchedEventLister run
info: Trigger thread listening. . . . 2016-09-05 09:41:10
September 05, 2016 9:41:10 AM job.SchedEventLister run
info: Trigger thread listening. . . . , status: normal
# Fourth execution
September 05, 2016 9:41:15 am job.SimpleJob execute
information: ===================: job.SimpleJob was just triggered...
September 05, 2016 9:41:15 AM job.SchedEventLister <init>
info: Trigger thread listener started....
September 05, 2016 9:41:15 AM job.SimpleJob execute
info: task Group Name: Job-Group-Simple, Task Name: SimpleJob, Trigger Group Name: Trriger-Group-Simple, Trigger Name: SimpleTrigger Execution Time: 2016-09-05 09:41:15, Count: 4
Sep 05, 2016 9:41:15 AM job.SchedEventLister run
info: Trigger thread listening. . . . 2016-09-05 09:41:15
Sep 05, 2016 9:41:15 AM job.SimpleJob execute
critical: Stopping and removing trigger..., trigger group name: Trriger-Group-Simple, trigger Name of the device: SimpleTriggerSeptember
05, 2016 9:41:15 am job.SchedEventLister run
information: The trigger thread is listening. . . . , status: no trigger
Sep 05, 2016 9:43:00 AM org.quartz.core.QuartzScheduler shutdown
info: Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
Sep 05, 2016 9:43:00 AM org.quartz.core .QuartzScheduler standby
info: Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
Sep 05, 2016 9:43:00 AM org.quartz.core.QuartzScheduler shutdown
info: Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
quartz.properties file: #Thread
pool implementation class
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool #Thread
pool number
org.quartz.threadPool.threadCount = 5 #Thread
pool priority
org.quartz.threadPool.threadPriority = 5
#The thread pool running mode is still in the foreground
org.quartz.threadPool.makeThreadsDaemons=false
###The inheritance property of the thread pool configuration
org.quartz.threadPool.threadsInheritGroupOfInitializingThread=true
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
## #Save job scheduling execution information to RAM. In this way, when the application restarts next time, job scheduling information is easy to lose
. org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.jobStore.misfireThreshold = 60000
## ##########.JobStoreTX, is to save the job scheduling information to RDB, and the job can be rescheduled when the application restarts
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.dataSource=test
#org.quartz.dataSource.test.driver=com.mysql.jdbc.Driver
#org.quartz.dataSource.test.URL=jdbc\:mysql\://localhost\:3306/test?useUnicode\=true&characterEncoding\=utf8&characterSetResults\=utf8
#org.quartz.dataSource.test.user=root
#org.quartz.dataSource.test.password=123456
#org.quartz.dataSource.test.maxConnections=20