Spring Quartz定時任務不許時執行

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個任務才被處理。

相關文章
相關標籤/搜索