最近幾天項目裏的定時器常常發生異常,比如:
1、修改linux系統時間時,定時任務全掛掉不動了。
2、在頁面裏面動態修改任務時間,常常不執行了。
下面是一些網友的資料,暫時收集放着,有時間將去驗證和修改自己系統的問題。
近日碰到一位友人提出的一個問題,如何動態的改變Quartz的調度作業的時間。比如,由每10分鐘執行一次改爲每5分鐘執行一次。個人認爲這種需求應該 通過某種方式來規避,或者選用其他的技術框架,因爲動態改變Quartz的調度時間完全失去了使用Quartz的意義。本人在使用Quartz是基於
Spring來配置的,而朋友的項目中不能使用SPring框架,這就需要直接基於Quartz編程。工作之餘,寫了個例子:
Quartz的管理類
- public class QuartzManage {
- private static SchedulerFactory sf = new StdSchedulerFactory();
- private static String JOB_GROUP_NAME = "group" ;
- private static String TRIGGER_GROUP_NAME = "trigger" ;
- public static void startJob(String jobName, Job job, String time)
- throws SchedulerException, ParseException {
- Scheduler sched = sf.getScheduler();
- JobDetail jobDetail = new JobDetail();
- jobDetail.setName(jobName);
- jobDetail.setGroup(JOB_GROUP_NAME);
- jobDetail.setJobClass(job.getClass());
- CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);
- trigger.setCronExpression(time);
- sched.scheduleJob(jobDetail, trigger);
- if (!sched.isShutdown()) {
- sched.start();
- }
- }
- /**
- * 從Scheduler 移除當前的Job,修改Trigger
- *
- * @param jobDetail
- * @param time
- * @throws SchedulerException
- * @throws ParseException
- */
- public static void modifyJobTime(JobDetail jobDetail, String time)
- throws SchedulerException, ParseException {
- Scheduler sched = sf.getScheduler();
- Trigger trigger = sched.getTrigger(jobDetail.getName(),
- TRIGGER_GROUP_NAME);
- if (trigger != null ) {
- CronTrigger ct = (CronTrigger) trigger;
- // 移除當前進程的Job
- sched.deleteJob(jobDetail.getName(), jobDetail.getGroup());
- // 修改Trigger
- ct.setCronExpression(time);
- System.out.println("CronTrigger getName " + ct.getJobName());
- // 重新調度jobDetail
- sched.scheduleJob(jobDetail, ct);
- }
- }
- }
Job任務:
- public class JobTest implements Job {
- static int a = 0 ;
- @Override
- public void execute(JobExecutionContext context)
- throws JobExecutionException {
- a += 1 ;
- System.out.println("test ++++++++++++++++++++++a=" + a);
- if (a == 4 ) {
- try {
- QuartzManage.modifyJobTime(context.getJobDetail(),
- "0/10 * * * * ?" );
- } catch (SchedulerException e) {
- e.printStackTrace();
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
- }
- }
啓動線程執行調度:
- public class QuartzTest {
- public static void main(String[] args) throws SchedulerException,
- ParseException {
- /*
- * 此進程爲主進程,觸發了quartz對Job的調度 因此啓動Job之後,在該進程修改調度,是沒有效果的
- */
- JobTest job = new JobTest();
- QuartzManage.startJob("ming" , job, "0/2 * * * * ?" );
- }
- }
好多人的思路是在啓動的主線程內去改變調度的時間,簡單的分析就可發現,主線程啓動之後就會按照調度時間去運行Job,不會返回主線程再去加載調度時間,只是起到了觸發調度的操作。因此要進行動態的修改調度時間,需要在Job任務裏,動態改變當前線程的調度計劃。
測試代碼,開始時按每2秒執行一次打印a,當a打印4次以後,按照每10秒一次執行。雖然代碼測試成功,本人還有疑惑。
- // 移除當前進程的Job
- sched.deleteJob(jobDetail.getName(), jobDetail.getGroup());
先移除當前的Job任務,在按照新的調度時間加入新的Job,雖然可以實現動態的改變,不知道是否帶來了其他的問題。
歡迎大家批評指正共同測試、驗證!