Quartz is a richly featured, open source job scheduling library that can be integrated within virtually any Java application - from the smallest stand-alone application to the largest e-commerce system.java
Quartz 是一個功能豐富,開源的任務調度的庫, 能夠和任何Java應用整合 .git
項目地址 : github.com/quartz-sche…github
快速開始地址 : github.com/quartz-sche…spring
Demo地址 : github.com/quartz-sche…編程
public class StdSchedulerTest {
public static void main(String[] args) {
try {
//1. StdSchedulerFactory工廠機制加載一個Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
// 2. JobBuilder 定義一個JobDetail , 工做信息
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// 3. TriggerBuilder定義一個trigger , 觸發器 , 告訴你這個Job什麼時候觸發
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger1", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(1000)
.repeatForever())
.build();
// 4.告訴Scheduler , 我這個工做須要這個trigger
scheduler.scheduleJob(job, trigger);
//5. 啓動
scheduler.start();
// 這裏咱們先阻塞着..
System.in.read();
// 6. 關閉
scheduler.shutdown();
} catch (SchedulerException | IOException se) {
se.printStackTrace();
}
}
}
複製代碼
其中 com.example.springquartz.HelloJob
須要實現org.quartz.Job
此接口安全
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobKey key = jobExecutionContext.getJobDetail().getKey();
System.out.printf("group %s , name : %s ,\t", key.getGroup(), key.getName());
System.out.printf("Thread : %s - %s\n", Thread.currentThread().getName(), "Hello Job !");
}
}
複製代碼
啓動 : 日誌信息 : 會告訴你任務什麼時候調用的.服務器
11:12:09.682 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
11:12:09.682 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.0
11:12:09.697 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
11:12:09.697 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
11:12:09.697 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'group1.job1', class=com.example.springquartz.HelloJob
11:12:09.713 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
11:12:09.713 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job group1.job1
group group1 , name : job1 , Thread : DefaultQuartzScheduler_Worker-1 - Hello Job !
複製代碼
能夠經過 org.quartz.JobBuilder#usingJobData(java.lang.String, java.lang.Long)
給Job賦值參數. 對於咱們這個使用的若是是靜態的數據, 好比說數據一層不變, 或者說任務先後關係不是依賴的. 能夠不考慮同步問題.多線程
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("job1", "group1")
.usingJobData(HelloJob.START_TIME, System.currentTimeMillis())
.build();
複製代碼
若是選擇了同步, 請選擇在你的Job中這倆註解 , 保持其同步關係.app
@PersistJobDataAfterExecution // 這個但願刷新JobData,因此多線程環境下共享是安全
@DisallowConcurrentExecution // 這個保證其同步執行, 其實就是任務挨着任務.
複製代碼
咱們對比使用一下. 不使用同步框架
public class HelloJob implements Job {
public static final String START_TIME = "START_TIME";
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
long start = jobExecutionContext.getMergedJobDataMap().getLong(START_TIME);
long flag = System.currentTimeMillis()-start;
System.out.printf("Thread-%d start : %s - %dms\n", tag, Thread.currentThread().getName(), System.currentTimeMillis() - start);
sleep(2000);
System.out.printf("Thread-%d end : %s - %dms\n", tag, Thread.currentThread().getName(), System.currentTimeMillis() - start);
}
}
複製代碼
輸出 : 因此他們並不會由於任務延時致使同步執行, 這些任務之間都是不互相依賴的.
Thread-15 start : DefaultQuartzScheduler_Worker-1 - 15ms
Thread-1002 start : DefaultQuartzScheduler_Worker-2 - 1002ms
Thread-2001 start : DefaultQuartzScheduler_Worker-3 - 2001ms
Thread-15 end : DefaultQuartzScheduler_Worker-1 - 2016ms
Thread-1002 end : DefaultQuartzScheduler_Worker-2 - 3010ms
Thread-2001 end : DefaultQuartzScheduler_Worker-3 - 4002ms
複製代碼
可是, 當咱們加入了
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class HelloJob implements Job {
public static final String START_TIME = "START_TIME";
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
long start = jobExecutionContext.getMergedJobDataMap().getLong(START_TIME);
long flag = System.currentTimeMillis()-start;
System.out.printf("Thread-%d start : %s - %dms\n", flag, Thread.currentThread().getName(), System.currentTimeMillis() - start);
sleep(2000);
System.out.printf("Thread-%d end : %s - %dms\n", flag, Thread.currentThread().getName(), System.currentTimeMillis() - start);
}
}
複製代碼
輸出 : 因此同步執行 ,
Thread-27 start : DefaultQuartzScheduler_Worker-1 - 28ms
Thread-27 end : DefaultQuartzScheduler_Worker-1 - 2032ms
Thread-2033 start : DefaultQuartzScheduler_Worker-2 - 2033ms
Thread-2033 end : DefaultQuartzScheduler_Worker-2 - 4034ms
複製代碼
總結一下 , 他的功能性, 以及特性都十分的強. 能夠保證其同步也能夠不一樣步, 這裏就要對比一下 . ScheduledExecutorService
-> java.util.concurrent.ScheduledThreadPoolExecutor
-> java.util.concurrent.ScheduledExecutorService
他的任務調度所有是同步執行的. 第二個任務必須等待第一個任務執行完畢才行. 我後面給你們展現
他的顆粒度掌握的很是的好 .
計劃任務,是任務在約定的時間執行已經計劃好的工做,這是表面的意思。在Linux中,咱們常常用到 cron 服務器來完成這項工做。cron服務器能夠根據配置文件約定的時間來執行特定的任務。
怎麼使用? , 固然是觸發器裏面了 , 咱們任務調度是靠的Triggers
// 這裏是每2S執行一次
Trigger trigger = TriggerBuilder.newTrigger()
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
複製代碼
輸出:
DefaultQuartzScheduler_Worker-1 : Echo com.example.springquartz.EchoJob@5f02d7f6
DefaultQuartzScheduler_Worker-2 : Echo com.example.springquartz.EchoJob@1d653213
DefaultQuartzScheduler_Worker-3 : Echo com.example.springquartz.EchoJob@7d2e9543
複製代碼
其實發現Quartz框架對於每個任務對象來講,他不是單例的, 每次都會依靠反射生成一個
簡單的編程實現
SimpleScheduleBuilder.simpleSchedule()
// 2S 一次
.withIntervalInMilliseconds(2000)
// 永遠執行下去
.repeatForever()
// 0 表明執行一次, 1表明執行兩次
// .withRepeatCount(1)
複製代碼
JobExecutionException e = new JobExecutionException("exception");
//e.refireImmediately(); // 失敗了能夠重複執行 , This will force quartz to run this job over and over and over and over again.
e.setUnscheduleAllTriggers(true); // 失敗了立馬中止trigger ,This will force quartz to shutdown this job so that it does not run again.
複製代碼
這個異常須要放到 Job中拋出去, 只能拋出這個異常才能控制是否執行
Set the Trigger's priority. When more than one Trigger have the same fire time, the scheduler will fire the one with the highest priority first.
倆任務一塊觸發, 優先觸發優先級高的任務 .
TriggerBuilder.newTrigger()
.usingJobData(EchoJob.FAVORITE_COLOR,"RED")
.forJob("JOB")
.startNow()
// 設置優先級
.withPriority(0)
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
複製代碼
Instructs the Scheduler that upon a mis-fire situation, the SimpleTrigger wants to be fired now by Scheduler.
有幾種, 我也不知道他這個有啥用 , 誤觸發.