1.更新任务
先前我们在更新任务时,虽然更新了定时任务的执行时间,但是并没有对参数进行更新,即使用context.getMergedJobDataMap().get(...)方法获取到的参数还是旧的。
假设我们更新了任务的时间表达式,任务已按新的时间表达式在执行,但在获取到参数后发现时间表达式还是原来的。
尝试对参数进行更新,使用如下代码:
JobDetail jobDetail = scheduler.getJobDetail(getJobKey(jobName, jobGroup)); //jobDetail = jobDetail.getJobBuilder().ofType(jobClass).build(); //更新参数 实际测试中发现无法更新 JobDataMap jobDataMap = jobDetail.getJobDataMap(); jobDataMap.put(ScheduleJobVo.JOB_PARAM_KEY, param); jobDetail.getJobBuilder().usingJobData(jobDataMap);
发现无法更新,试过其它几个api发现都不行,没有办法,最后采用了先删除任务再进行创建的方式来迂回实现参数的更新。更新任务有直接修改方式和删除修改方式,区别就在这里。下面先删后加的方式更新Job
Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); scheduler.deleteJob(jobKey); //修改cronTrigger //根据TriggerKey和Trigger重新添加一个Job到scheduler scheduler.addJob...
2.任务的同步和异步
在定时任务运行时更新是没有办法改变同步和异步的
同步和异步在quartz 2.2的版本中对于使用者来说区别只在于是否在job类上添加了@DisallowConcurrentExecution注解
整合使用时,碰到的一些问题:
一、更新任务时参数问题。也就是前面说的无法更新任务中传入的参数。
二、同步或异步在定时任务运行时修改是不能改变的,这个在前面也提到了。
三、在定时任务运行时修改,可能会该让任务长时间处于线程阻塞状态,即BLOCKED状态,即使你的任务中只有简单的一行System.out输出。要使它恢复也很简单,删除重建即可。
四、定时任务运行两次的问题。这个也是网上传的最多的问题,这里来着重的说一下。
网上流传引起该问题的原因目前主要有两个说法:
1 spring配置文件加载了多次,导致quartz的bean被实例化多次而导致任务多次执行。
2 tomcat的webapps目录问题。tomcat运行时加载了两次配置文件导致任务多次执行。
这两个说法在我的demo中应该并不存在,但为了验证我也尝试了下。
不使用tomcat,在main方法中用编程的方式启动spring,甚至不使用spring,直接用quartz官方给出的代码:
try { // Grab the Scheduler instance from the Factory Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // and start it off scheduler.start(); scheduler.shutdown(); } catch (SchedulerException se) { se.printStackTrace(); }
问题还是存在,这就说明不是配置文件加载的问题了,这应该是quartz本身存在的一个bug,而且这个多次运行是很有规律的,基本按如下套路走:
定为5秒运行一次,一切正常,没有多次执行现象发生。
定为10秒运行一次,一切正常,没有多次执行现象发生。
定为29秒运行一次,运行时一次正常,一次不正常。
定为59秒运行一次,运行时一次正常,一次不正常。
以上是我实测得出的,再长时间就没测了,毕竟太耗时。在有运行两次的现象时都是间隔的,即一次正常一次不正常这种方式。
既然推断是quartz本身存在bug,那我们又要如何解决这个问题了?
其实在我个人看来,这个问题是无关紧要的,为什么说无关紧要呢?这就涉及到你项目业务设计的是否完善,代码是否健壮了。
一个设计良好的业务方法,特别是那些供外部调用的接口或方法,应该都支持幂等性,何为幂等性?即这个方法同样的参数至少在一个时间区间内,我调用1次和调用10次100次,结果都是一样的。
支持了幂等性,前面说的运行两次的情况是不是就无关紧要了?在有些定时任务为分布式设计的系统(后面会探讨)中,为了确保定时任务的执行甚至会故意人为的去调用两次。
当然支持幂等性最好是在进入方法时就判断,发现已经执行过时就立即返回而不是真的再去同样的结果再执行一遍,以节省资源。