关于Quartz任务不准时执行问题

1.前言

也是前段时间工作上遇到这样的问题:quartz定时任务没有在预期的时间执行。后来研究了下quartz的机制,查明了原因,在这做个记录和分享。

2. 原因解释

    先看一下spring quartz的大致机制或者说原理。quartz任务由一个主线程和线程池中的多个具体的工作线程构成。

    主线程是QuartzSchedulerThread, 主要负责获取具体的定时任务和该任务执行的时间(比如可以通过cron expression 得到时间),并分发任务给线程池。

    具体的任务由线程池中的工作线程执行,默认的线程池类是SimpleThreadPool,工作线程是其内部类WorkerThread,默认线程数是10. WorkerThread会领取具体工作任务并执行。

 

    假设10个WorkerThread都在处理任务中(还没处理完各自的任务),假设所有任务都是无状态的(stateless)。而此时第11个任务来到,那么此时就没有空闲的WorkerThread能处理这个任务了。这样造成的现象是:在预期任务执行的时候,任务并没有执行,任务延时了。第11个任务会在某个WorkerThread处理完其任务时,被该WorkerThread领取并处理。

 

   当时工作上遇到的问题即是这样,某些任务花费了很长的时间处理,以至于工作线程全部处在“忙碌”状态,没有空闲线程来及时处理新的任务。

  * 默认线程池类,工作线程数都是在quartz jar包中的quartz.properties文件里设置。

 

3. 代码测试和验证

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个任务才被处理。



文章转自:https://my.oschina.net/u/1162561/blog/287588



昨天在工作中突然发现,      如果本地先运行项目,然后修改服务器时间的话,这个作业是不会执行的(即,运行项目时,作业时间必定是晚于当前项目的,),    作业时间是如何获取的可以研究一下。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值