使用Quartz作为任务调度时 fireTime的一个坑

         一个任务调度的业务场景:需要在每个小时后2秒钟从数据库中取得当前小时的数据并进行计算,此时使用Quartz做为任务调度,设置每个小时执行一次,sleep2秒以后执行业务代码。并使用Quartz提供的fireTime作为时间条件获取数据。

先看示例代码:

public class QuartzTest {
	public static void main(String[] args) throws SchedulerException {
		//String cron="00 00 * * * ?";
		//为了测试使用就近时间。
		String cron="00 17 * * * ?";
		StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); 
		Scheduler stdSchedulerFactory=sf.getScheduler();
	       //50个任务
		for(int i=1;i<50;i++){
			JobDetail jobDetail=JobBuilder.newJob(Job1.class).build();
			Trigger trigger=TriggerBuilder.newTrigger()
					.withSchedule(CronScheduleBuilder.cronSchedule(cron))
					.build();
			sched.scheduleJob(jobDetail,trigger);
		}
		sched.start();
	}

}

Job1.class

public class Job1  implements Job{
	public void execute(JobExecutionContext context)
			throws JobExecutionException {
		SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String dateStr=sf.format(context.getFireTime());
		//记录任务调度的时间
		System.out.println(dateStr);
		try {
		    Thread.sleep(2000);
	            //do someting  with dateStr.... 
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

得到的结果:

2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:00
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:01
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:02
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:03
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04
2015-02-01 04:27:04

通过结果发现 拿到的fireTime和预期不一样。

这个时候如果使用fireTime去获取数据就会拿到有误差的数据,也会造成业务结果错误。

通过分析发现 Quartz(v2.1.1) 默认使用的是自带线程池的实现:SimpleThreadPool,并且默认为10个线程,在并发任务达到 10 个以后,再有触发的任务就无法被执行了,只能等待有空闲线程的时候才能得到执,这也是为什么结果中只有前10个结果是符合预期的。

我们可以添加配置文件来修改Quartz的一些默认配置项,并发数:

org.quartz.threadPool.threadCount=50;

也可以直接在代码中修改:

StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory(); 
Properties pro=new Properties();
pro.setProperty("org.quartz.threadPool.threadCount", "50");
stdSchedulerFactory.initialize(pro);

 但是必须指出一点,这个初始线程数并不是越大越好。当并发线程太多时,系统整体性能反而会下降,因为系统把很多时间花在了线程调度上。

转载于:https://my.oschina.net/caiw/blog/374165

你可能感兴趣的:(使用Quartz作为任务调度时 fireTime的一个坑)