1. 前言java
也是前段時間工做上遇到過這樣的問題:quartz定時任務沒有在預期的時間執行。後來研究了下quartz的機制,查明瞭緣由,這裏作個記錄和分享。spring
2. 緣由解釋sql
先看一下spring quartz的大體機制或者說原理。quartz任務由一個主線程和線程池中的多個具體的工做線程構成。express
主線程是QuartzSchedulerThread, 主要負責獲取具體的定時任務和該任務執行的時間(好比能夠經過cron expression 獲得時間),並分發任務給線程池。less
具體的任務由線程池中的工做線程執行,默認的線程池類是SimpleThreadPool,工做線程是其內部類WorkerThread,默認線程數是10. WorkerThread會領取具體工做任務並執行。測試
假設10個WorkerThread都在處理任務中(還沒處理完各自的任務),假設全部任務都是無狀態的(stateless)。而此時第11個任務來到,那麼此時就沒有空閒的WorkerThread能處理這個任務了。這樣形成的現象是:在預期任務執行的時候,任務並無執行,任務延時了。第11個任務會在某個WorkerThread處理完其任務時,被該WorkerThread領取並處理。spa
當時工做上遇到的問題便是這樣,某些任務花費了很長的時間處理,以致於工做線程所有處在「忙碌」狀態,沒有空閒線程來及時處理新的任務。線程
* 默認線程池類,工做線程數都是在quartz jar包中的quartz.properties文件裏設置。code
3. 代碼測試和驗證get
package test; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; public class TestCronJob { public static void main(String[] args){ SchedulerFactory sf = new StdSchedulerFactory(); try { // below including instantiate QuartzScheduler, // where quartz QuartzSchedulerThread is instantiated. Scheduler sched = sf.getScheduler(); sched.start(); JobDetail jd = new JobDetail("myjob",sched.DEFAULT_GROUP,MyJob.class); System.out.println("stateful:"+jd.isStateful()); CronTrigger ct = new CronTrigger("JobName","DEFAULT","*/10 * * * * ? *"); sched.scheduleJob(jd, ct); }catch(Exception e){ e.printStackTrace(); } } } package test; import java.sql.Timestamp; import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.StatefulJob; public class MyJob implements Job{ public void execute(JobExecutionContext arg0) throws JobExecutionException{ System.out.println(new Timestamp(System.currentTimeMillis())+",job executed [" + Thread.currentThread().getName()+"]"); try { Thread.sleep(2*60*1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(new Timestamp(System.currentTimeMillis())+",job executed ["+Thread.currentThread().getName()+"]"); } }
上述代碼的效果是:
每10秒執行一下MyJob的任務,MyJob負責打印一些信息。注意執行該任務要花費2分鐘(休眠的緣故)。
根據最終輸出能夠看到,前10個任務準時執行,彼此間隔10s。而第11個任務延時了30s,直到某一個任務執行完以後,第11個任務才被處理。