springboot實(shí)現(xiàn)定時(shí)任務(wù)的四種方式小結(jié)
因?yàn)槟承┬枨螅谔囟ǖ臅r(shí)間執(zhí)行一些任務(wù),比如定時(shí)刪除服務(wù)器存儲(chǔ)的數(shù)據(jù)緩存,定時(shí)獲取數(shù)據(jù)以及定時(shí)發(fā)送推送等等,這時(shí)就需要用到定時(shí)任務(wù)了。定時(shí)任務(wù),指的是在編程過(guò)程中無(wú)須做復(fù)雜控制的前提下執(zhí)行簡(jiǎn)單的定時(shí)操作。
Timer
在java中一個(gè)完整的定時(shí)任務(wù)可以用Timer和TimerTask兩個(gè)類配合完成。
Timer是一種工具,線程用其安排在后臺(tái)線程中執(zhí)行的任務(wù),可安排任務(wù)執(zhí)行一次或者定期重復(fù)執(zhí)行。
TimerTask是由Timer安排執(zhí)行一次或者重復(fù)執(zhí)行的任務(wù)。
Timer中提供了四個(gè)方法:
(1)schedule(TimerTask task,Date time)——安排在指定的時(shí)間執(zhí)行指定的任務(wù)
(2)schedule(TimerTask task,Date firstTime,long period)——安排指定的任務(wù)在指定的時(shí)間開始進(jìn)行重復(fù)的固定延遲執(zhí)行
(3)schedule(TimerTask task,long delay)——安排在指定延遲后執(zhí)行指定的任務(wù)
(4)schedule(TimerTask task,long delay,long period)——安排指定的任務(wù)在指定的延遲后開始進(jìn)行重復(fù)的固定速率執(zhí)行
示例:
首先需要?jiǎng)?chuàng)建一個(gè)類作為定時(shí)任務(wù),該類需要繼承TimerTask
public class TimerTask extends java.util.TimerTask{?
?? ?@Override
?? ?public void run() {
?? ??? ?//這里執(zhí)行定時(shí)任務(wù)內(nèi)容
?? ??? ?System.out.println("+++++++");
?? ?}?? ?
}然后創(chuàng)建Timer調(diào)用之前創(chuàng)建的定時(shí)任務(wù)
public class TimerTest {
?? ?
?? ?public static void main(String[] args) {
?? ??? ?Timer timer = new Timer();
?? ??? ?TimerTask noticeTask = new TimerTask();
?? ??? ?timer.schedule(noticeTask,0,2000);
?? ??? ?timer.cancel();
?? ??? ?System.out.println("結(jié)束");?? ?
?? ?}
?
}這樣定時(shí)執(zhí)行任務(wù)的功能就實(shí)現(xiàn)了,但Timer有著一定的缺陷:
Timer對(duì)于系統(tǒng)時(shí)間的改變非常敏感,它對(duì)調(diào)度的支持是基于絕對(duì)時(shí)間而不是相對(duì)時(shí)間。
Timer線程是不會(huì)捕獲異常的,多線程并行處理定時(shí)任務(wù)時(shí),Timer運(yùn)行多個(gè)TimerTask時(shí),只要其中之一沒(méi)有捕獲拋出的異常,其他任務(wù)便會(huì)自動(dòng)終止運(yùn)行。同時(shí)Timer也不會(huì)重新恢復(fù)線程的執(zhí)行,它會(huì)錯(cuò)誤的認(rèn)為整個(gè)Timer線程都會(huì)取消,已經(jīng)被安排但尚未執(zhí)行的TimerTask也不會(huì)再執(zhí)行了,新的任務(wù)也不能被調(diào)度。因此,如果TimerTask拋出未檢查的異常,Timer將會(huì)產(chǎn)生無(wú)法預(yù)料的行為。
ScheduledExecutor
Timer是基于絕對(duì)時(shí)間的,對(duì)系統(tǒng)時(shí)間比較敏感,而ScheduledExecutor則是基于相對(duì)時(shí)間。
Timer的內(nèi)部只有一個(gè)線程,如果有多個(gè)任務(wù)的話就會(huì)順序執(zhí)行,這樣我們的延遲時(shí)間和循環(huán)時(shí)間就會(huì)出現(xiàn)問(wèn)題。而ScheduledThreadPoolExecutor內(nèi)部是個(gè)線程池,可以支持多個(gè)任務(wù)并發(fā)執(zhí)行,在對(duì)延遲任務(wù)和循環(huán)任務(wù)要求嚴(yán)格的時(shí)候,就需要考慮使用ScheduledExecutor了。
針對(duì)Timer類存在的缺陷,Java 5 推出了基于線程池設(shè)計(jì)的 ScheduledExecutor,ScheduledExecutor的設(shè)計(jì)思想是每一個(gè)被調(diào)度的任務(wù)都會(huì)由線程池中一個(gè)線程去執(zhí)行,因此任務(wù)是并發(fā)的,相互之間不會(huì)受到干擾,只有當(dāng)任務(wù)的時(shí)間到來(lái)時(shí),ScheduledExecutor才會(huì)真正啟動(dòng)一個(gè)線程,其余時(shí)間ScheduledExecutor都是處于輪詢?nèi)蝿?wù)的狀態(tài)。如果我們?cè)O(shè)定的調(diào)度周期小于任務(wù)運(yùn)行時(shí)間,該任務(wù)會(huì)被重復(fù)添加到一個(gè)延時(shí)任務(wù)隊(duì)列,所以同一時(shí)間任務(wù)隊(duì)列中會(huì)有多個(gè)任務(wù)待調(diào)度,線程池會(huì)首先獲取優(yōu)先級(jí)高的任務(wù)執(zhí)行。效果就是任務(wù)運(yùn)行多長(zhǎng)時(shí)間,調(diào)度時(shí)間就會(huì)變?yōu)槎嗑?,因?yàn)樘砑拥饺蝿?wù)隊(duì)列的任務(wù)的延時(shí)時(shí)間每次都是負(fù)數(shù),所以會(huì)被立刻執(zhí)行。
示例:
public class MyScheduledExecutor implements Runnable{
?? ?
? ? private String jobName;
? ??
? ? MyScheduledExecutor() {
? ? ? ??
? ? }
? ??
? ? MyScheduledExecutor(String jobName) {
? ? ? ? this.jobName = jobName;
? ? }
?
? ? @Override
? ? public void run() {
?? ? ? ?System.out.println(jobName + " is running");
? ? }
?
}public class MyScheduledExecutorService {
public static void main(String[] args) {
long initialDelay = 3;
long period = 1;
/**
* 創(chuàng)建一個(gè)線程池,它可安排在給定延遲后運(yùn)行任務(wù)或者定期地執(zhí)行任務(wù)
* 參數(shù):corePoolSize - 池中所保存的線程數(shù),即使線程是空閑的也包括在內(nèi)
*/
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 從現(xiàn)在開始3秒鐘之后,每隔1秒鐘執(zhí)行一次job1,ScheduleAtFixedRate是基于固定時(shí)間間隔進(jìn)行任務(wù)調(diào)度
* 參數(shù):1、任務(wù)體 2、首次執(zhí)行的延時(shí)時(shí)間
* 3、任務(wù)執(zhí)行間隔 4、間隔時(shí)間單位
*/
service.scheduleAtFixedRate(new MyScheduledExecutor("job1"), initialDelay, period, TimeUnit.SECONDS);
/**
* 從現(xiàn)在開始3秒鐘之后,每隔1秒鐘執(zhí)行一次job2,ScheduleWithFixedDelay 取決于每次任務(wù)執(zhí)行的時(shí)間長(zhǎng)短,基于不固定時(shí)間間隔進(jìn)行任務(wù)調(diào)度
*/
service.scheduleWithFixedDelay(new MyScheduledExecutor("job2"), initialDelay, period, TimeUnit.SECONDS);
}
}ScheduledExecutor 配合 Calendar 實(shí)現(xiàn)復(fù)雜任務(wù)調(diào)度
示例:設(shè)置每星期二的 18:30:00 執(zhí)行任務(wù)
使用 ScheduledExcetuor 和 Calendar 進(jìn)行任務(wù)調(diào)度
public class ScheduledExceutorTest2 extends TimerTask {
?
?? ?private String jobName = "";
?
?? ?public ScheduledExceutorTest2(String jobName) {
?? ??? ?super();
?? ??? ?this.jobName = jobName;
?? ?}
?
?? ?@Override
?? ?public void run() {
?? ??? ?System.out.println("Date = " + new Date() + ", execute " + jobName);
?? ?}
?
?? ?/**
?? ? * 計(jì)算從當(dāng)前時(shí)間currentDate開始,滿足條件dayOfWeek, hourOfDay, minuteOfHour,
?? ? * secondOfMinite的最近時(shí)間
?? ? */
?? ?public Calendar getEarliestDate(Calendar currentDate, int dayOfWeek, int hourOfDay, int minuteOfHour,
?? ??? ??? ?int secondOfMinite) {
?? ??? ?// 計(jì)算當(dāng)前時(shí)間的WEEK_OF_YEAR,DAY_OF_WEEK, HOUR_OF_DAY, MINUTE,SECOND等各個(gè)字段值
?? ??? ?int currentWeekOfYear = currentDate.get(Calendar.WEEK_OF_YEAR);
?? ??? ?int currentDayOfWeek = currentDate.get(Calendar.DAY_OF_WEEK);
?? ??? ?int currentHour = currentDate.get(Calendar.HOUR_OF_DAY);
?? ??? ?int currentMinute = currentDate.get(Calendar.MINUTE);
?? ??? ?int currentSecond = currentDate.get(Calendar.SECOND);
?? ??? ?// 如果輸入條件中的dayOfWeek小于當(dāng)前日期的dayOfWeek,則WEEK_OF_YEAR需要推遲一周
?? ??? ?boolean weekLater = false;
?? ??? ?if (dayOfWeek < currentDayOfWeek) {
?? ??? ??? ?weekLater = true;
?? ??? ?} else if (dayOfWeek == currentDayOfWeek) {
?? ??? ??? ?// 當(dāng)輸入條件與當(dāng)前日期的dayOfWeek相等時(shí),如果輸入條件中的
?? ??? ??? ?// hourOfDay小于當(dāng)前日期的
?? ??? ??? ?// currentHour,則WEEK_OF_YEAR需要推遲一周
?? ??? ??? ?if (hourOfDay < currentHour) {
?? ??? ??? ??? ?weekLater = true;
?? ??? ??? ?} else if (hourOfDay == currentHour) {
?? ??? ??? ??? ?// 當(dāng)輸入條件與當(dāng)前日期的dayOfWeek, hourOfDay相等時(shí),
?? ??? ??? ??? ?// 如果輸入條件中的minuteOfHour小于當(dāng)前日期的
?? ??? ??? ??? ?// currentMinute,則WEEK_OF_YEAR需要推遲一周
?? ??? ??? ??? ?if (minuteOfHour < currentMinute) {
?? ??? ??? ??? ??? ?weekLater = true;
?? ??? ??? ??? ?} else if (minuteOfHour == currentSecond) {
?? ??? ??? ??? ??? ?// 當(dāng)輸入條件與當(dāng)前日期的dayOfWeek, hourOfDay,
?? ??? ??? ??? ??? ?// minuteOfHour相等時(shí),如果輸入條件中的
?? ??? ??? ??? ??? ?// secondOfMinite小于當(dāng)前日期的currentSecond,
?? ??? ??? ??? ??? ?// 則WEEK_OF_YEAR需要推遲一周
?? ??? ??? ??? ??? ?if (secondOfMinite < currentSecond) {
?? ??? ??? ??? ??? ??? ?weekLater = true;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if (weekLater) {
?? ??? ??? ?// 設(shè)置當(dāng)前日期中的WEEK_OF_YEAR為當(dāng)前周推遲一周
?? ??? ??? ?currentDate.set(Calendar.WEEK_OF_YEAR, currentWeekOfYear + 1);
?? ??? ?}
?? ??? ?// 設(shè)置當(dāng)前日期中的DAY_OF_WEEK,HOUR_OF_DAY,MINUTE,SECOND為輸入條件中的值。
?? ??? ?currentDate.set(Calendar.DAY_OF_WEEK, dayOfWeek);
?? ??? ?currentDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
?? ??? ?currentDate.set(Calendar.MINUTE, minuteOfHour);
?? ??? ?currentDate.set(Calendar.SECOND, secondOfMinite);
?? ??? ?return currentDate;
?? ?}
?
?? ?public static void main(String[] args) throws Exception {
?? ??? ?ScheduledExceutorTest2 test = new ScheduledExceutorTest2("job1");
?? ??? ?// 獲取當(dāng)前時(shí)間
?? ??? ?Calendar currentDate = Calendar.getInstance();
?? ??? ?long currentDateLong = currentDate.getTime().getTime();
?? ??? ?System.out.println("Current Date = " + currentDate.getTime().toString());
?? ??? ?// 計(jì)算滿足條件的最近一次執(zhí)行時(shí)間
?? ??? ?Calendar earliestDate = test.getEarliestDate(currentDate, 3, 18, 30, 00);
?? ??? ?long earliestDateLong = earliestDate.getTime().getTime();
?? ??? ?System.out.println("Earliest Date = " + earliestDate.getTime().toString());
?? ??? ?// 計(jì)算從當(dāng)前時(shí)間到最近一次執(zhí)行時(shí)間的時(shí)間間隔
?? ??? ?long delay = earliestDateLong - currentDateLong;
?? ??? ?// 計(jì)算執(zhí)行周期為一星期
?? ??? ?long period = 7 * 24 * 60 * 60 * 1000;
?? ??? ?ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
?? ??? ?// 從現(xiàn)在開始delay毫秒之后,每隔一星期執(zhí)行一次job1
?? ??? ?service.scheduleAtFixedRate(test, delay, period, TimeUnit.MILLISECONDS);
?? ?}
?
}其核心在于根據(jù)當(dāng)前時(shí)間推算出最近一個(gè)星期二 18:30:00 的絕對(duì)時(shí)間,然后計(jì)算與當(dāng)前時(shí)間的時(shí)間差,作為調(diào)用 ScheduledExceutor 函數(shù)的參數(shù),計(jì)算最近時(shí)間要用到 java.util.calendar 的功能。
注解@Scheduled
Spring提供的注解,優(yōu)點(diǎn)就是配置簡(jiǎn)單,依賴少,缺點(diǎn)是同一個(gè)task,如果前一個(gè)還沒(méi)跑完后面一個(gè)就不會(huì)觸發(fā),不同的task也不能同時(shí)運(yùn)行。因?yàn)閟cheduler的默認(rèn)線程數(shù)為1,配置pool-size為2的話,會(huì)導(dǎo)致同一個(gè)task前一個(gè)還沒(méi)跑完后面又被觸發(fā)的問(wèn)題,不支持集群等。
示例:
yml文件配置:
time: ? ? cron: 0/5 * * * * * ? ? interval: 5
啟動(dòng)類添加@EnableScheduling
定時(shí)任務(wù):
@Component
public class TimeTask {
?? ?
?? ?@Scheduled(cron = "${time.cron}")
?? ?public void ?flush1() throws ?Exception{
? ? ? ? ? ? System.out.println("Execute1");
? ? ? ? }
?? ?
?? ?@Scheduled(cron = "0/${time.interval} * * * * ?")
?? ?public void ?flush2() throws ?Exception{
? ? ? ? ? ? System.out.println("Execute2");
? ? ? ? }
?? ?
?? ?@Scheduled(cron = "0/5 * * * * ?")
?? ?public void ?flush3() throws ?Exception{
? ? ? ? ? ? System.out.println("Execute3");
? ? ? ? }
?
}參數(shù)介紹:
fixedDelay
上一次執(zhí)行完畢時(shí)間點(diǎn)之后多長(zhǎng)時(shí)間再執(zhí)行。如:
@Scheduled(fixedDelay = 5000) //上一次執(zhí)行完畢時(shí)間點(diǎn)之后5秒再執(zhí)行
fixedDelayString
與 fixedDelay 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。如:
@Scheduled(fixedDelayString = "5000") //上一次執(zhí)行完畢時(shí)間點(diǎn)之后5秒再執(zhí)行
占位符的使用:
@Scheduled(fixedDelayString = "${time.fixedDelay}")
void testFixedDelayString() {
System.out.println("Execute”);
}
fixedRate
上一次開始執(zhí)行時(shí)間點(diǎn)之后多長(zhǎng)時(shí)間再執(zhí)行。如:
@Scheduled(fixedRate = 5000) //上一次開始執(zhí)行時(shí)間點(diǎn)之后5秒再執(zhí)行
fixedRateString
與 fixedRate 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。
initialDelay
第一次延遲多長(zhǎng)時(shí)間后再執(zhí)行。如:
@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延遲1秒后執(zhí)行,之后按fixedRate的規(guī)則每5秒執(zhí)行一次
initialDelayString
與 initialDelayString 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。
cron表達(dá)式
cron表達(dá)式是一個(gè)字符串,字符串以5或6個(gè)空格隔開,分成6或7個(gè)域,每一個(gè)域代表一個(gè)含義。
cron表達(dá)式語(yǔ)法:
[秒] [分] [小時(shí)] [日] [月] [周] [年]
注:[年]不是必須的域,可以省略[年],則一共6個(gè)域
其中各個(gè)域的定義如下:
| 序號(hào) | 說(shuō)明 | 必填 | 允許填寫的值 | 允許的通配符 |
| 1 | 秒 | 是 | 0-59 | , - * / |
| 2 | 分 | 是 | 0-59 | , - * / |
| 3 | 時(shí) | 是 | 0-23 | , - * / |
| 4 | 日 | 是 | 1月31日 | , - * ? / L W |
| 5 | 月 | 是 | 1-12 / JAN-DEC | , - * / |
| 6 | 周 | 是 | 1-7 / SUN-SAT | , - * ? / L # |
| 7 | 年 | 否 | 1970-2099 | , - * / |
Cron表達(dá)式對(duì)特殊字符的大小寫不敏感,對(duì)代表星期的縮寫英文大小寫也不敏感。星號(hào)(*):可用在所有字段中,表示對(duì)應(yīng)時(shí)間域的每一個(gè)時(shí)刻,例如, 在分鐘字段時(shí),表示“每分鐘”;
問(wèn)號(hào)(?):該字符只在日期和星期字段中使用,它通常指定為“無(wú)意義的值”,相當(dāng)于點(diǎn)位符;
- 減號(hào)(-):表達(dá)一個(gè)范圍,如在小時(shí)字段中使用“10-12”,則表示從10到12點(diǎn),即10,11,12;
- 逗號(hào)(,):表達(dá)一個(gè)列表值,如在星期字段中使用“MON,WED,FRI”,則表示星期一,星期三和星期五;
- 斜杠(/):x/y表達(dá)一個(gè)等步長(zhǎng)序列,x為起始值,y為增量步長(zhǎng)值。如在分鐘字段中使用0/15,則表示為0,15,30和45秒,而5/15在分鐘字段中表示5,20,35,50,你也可以使用*/y,它等同于0/y;
- L:該字符只在日期和星期字段中使用,代表“Last”的意思,但它在兩個(gè)字段中意思不同。L在日期字段中,表示這個(gè)月份的最后一天,如一月的31號(hào),非閏年二月的28號(hào);如果L用在星期中,則表示星期六,等同于7。但是,如果L出現(xiàn)在星期字段里,而且在前面有一個(gè)數(shù)值X,則表示“這個(gè)月的最后X天”,例如,6L表示該月的最后星期五;
- W:該字符只能出現(xiàn)在日期字段里,是對(duì)前導(dǎo)日期的修飾,表示離該日期最近的工作日。例如15W表示離該月15號(hào)最近的工作日,如果該月15號(hào)是星期六,則匹配14號(hào)星期五;如果15日是星期日,則匹配16號(hào)星期一;如果15號(hào)是星期二,那結(jié)果就是15號(hào)星期二。但必須注意關(guān)聯(lián)的匹配日期不能夠跨月,如你指定1W,如果1號(hào)是星期六,結(jié)果匹配的是3號(hào)星期一,而非上個(gè)月最后的那天。W字符串只能指定單一日期,而不能指定日期范圍;
- LW組合:在日期字段可以組合使用LW,它的意思是當(dāng)月的最后一個(gè)工作日;
- 井號(hào)(#):該字符只能在星期字段中使用,表示當(dāng)月某個(gè)工作日。如6#3表示當(dāng)月的第三個(gè)星期五(6表示星期五,#3表示當(dāng)前的第三個(gè)),而4#5表示當(dāng)月的第五個(gè)星期三,假設(shè)當(dāng)月沒(méi)有第五個(gè)星期三,忽略不觸發(fā);
- C:該字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是計(jì)劃所關(guān)聯(lián)的日期,如果日期沒(méi)有被關(guān)聯(lián),則相當(dāng)于日歷中所有日期。例如5C在日期字段中就相當(dāng)于日歷5日以后的第一天。1C在星期字段中相當(dāng)于星期日后的第一天。
示例:
| 表示式 | 說(shuō)明 |
| 0 0 12 * * ? | 每天12點(diǎn)運(yùn)行 |
| 0 15 10 ? * * | 每天10:15運(yùn)行 |
| 0 15 10 * * ? | 每天10:15運(yùn)行 |
| 0 15 10 * * ? * | 每天10:15運(yùn)行 |
| 0 15 10 * * ? 2008 | 在2008年的每天10:15運(yùn)行 |
| 0 * 14 * * ? | 每天14點(diǎn)到15點(diǎn)之間每分鐘運(yùn)行一次,開始于14:00,結(jié)束于14:59。 |
| 0 0/5 14 * * ? | 每天14點(diǎn)到15點(diǎn)每5分鐘運(yùn)行一次,開始于14:00,結(jié)束于14:55。 |
| 0 0/5 14,18 * * ? | 每天14點(diǎn)到15點(diǎn)每5分鐘運(yùn)行一次,此外每天18點(diǎn)到19點(diǎn)每5鐘也運(yùn)行一次。 |
| 0 0-5 14 * * ? | 每天14:00點(diǎn)到14:05,每分鐘運(yùn)行一次。 |
| 0 10,44 14 ? 3 WED | 3月每周三的14:10分到14:44,每分鐘運(yùn)行一次。 |
| 0 15 10 ? * MON-FRI | 每周一,二,三,四,五的10:15分運(yùn)行。 |
| 0 15 10 15 * ? | 每月15日10:15分運(yùn)行。 |
| 0 15 10 L * ? | 每月最后一天10:15分運(yùn)行。 |
| 0 15 10 ? * 6L | 每月最后一個(gè)星期五10:15分運(yùn)行。 |
| 0 15 10 ? * 6L 2007-2009 | 在2007,2008,2009年每個(gè)月的最后一個(gè)星期五的10:15分運(yùn)行。 |
| 0 15 10 ? * 6#3 | 每月第三個(gè)星期五的10:15分運(yùn)行。 |
Quartz
Quartz 是一個(gè)完全由 Java 編寫的開源作業(yè)調(diào)度框架,它可以集成在幾乎任何Java應(yīng)用程序中進(jìn)行作業(yè)調(diào)度。
Quartz 可以與 J2EE 與 J2SE 應(yīng)用程序相結(jié)合也可以單獨(dú)使用。
Quartz 允許程序開發(fā)人員根據(jù)時(shí)間的間隔來(lái)調(diào)度作業(yè)。
Quartz 實(shí)現(xiàn)了作業(yè)和觸發(fā)器的多對(duì)多的關(guān)系,還能把多個(gè)作業(yè)與不同的觸發(fā)器關(guān)聯(lián)。
Quartz的運(yùn)行環(huán)境
Quartz 可以運(yùn)行嵌入在另一個(gè)獨(dú)立式應(yīng)用程序。
Quartz 可以在應(yīng)用程序服務(wù)器(或 servlet 容器)內(nèi)被實(shí)例化,并且參與 XA 事務(wù)。
Quartz 可以作為一個(gè)獨(dú)立的程序運(yùn)行(其自己的 Java 虛擬機(jī)內(nèi)),可以通過(guò) RMI 使用。
Quartz 可以被實(shí)例化,作為獨(dú)立的項(xiàng)目集群(負(fù)載平衡和故障轉(zhuǎn)移功能),用于作業(yè)的執(zhí)行。
Job
代表一個(gè)工作,要執(zhí)行的具體內(nèi)容。此接口中只有一個(gè)方法,如下:
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(new Date());
}
}
可以通過(guò)實(shí)現(xiàn)該接口來(lái)定義需要執(zhí)行的任務(wù)。
JobDetail
用于定義作業(yè)的實(shí)例,代表一個(gè)具體的可執(zhí)行的調(diào)度程序,Job 是這個(gè)可執(zhí)行程調(diào)度程序所要執(zhí)行的內(nèi)容,另外 JobDetail 還包含了這個(gè)任務(wù)調(diào)度的方案和策略。
Trigger
代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
1> SimpleTrigger:在某個(gè)時(shí)間段內(nèi)實(shí)現(xiàn)定時(shí)任務(wù)的重復(fù)執(zhí)行。
參數(shù):startTime(開始時(shí)間)、endTime(結(jié)束時(shí)間)、repeatCount(重復(fù)數(shù)次)、repeatInterval(重復(fù)執(zhí)行間隔)
2> CronTrigger:基于日歷的概念執(zhí)行計(jì)劃,這個(gè)trigger是最常用的。
參數(shù):startTime(開始時(shí)間)、endTime(結(jié)束時(shí)間)、cronExpression(定時(shí)表達(dá)式)、timeZone(時(shí)區(qū),默認(rèn)獲取jvm所在時(shí)區(qū))
Scheduler
代表一個(gè)調(diào)度容器,一個(gè)調(diào)度容器中可以注冊(cè)多個(gè) JobDetail 和 Trigger。當(dāng) Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調(diào)度了。
Calendar
是一些日歷特定時(shí)間的集合。一個(gè)Trigger可以和多個(gè)calendar關(guān)聯(lián),可以通過(guò)calendar在指定時(shí)間不執(zhí)行任務(wù)。
示例:服務(wù)啟動(dòng)5秒后執(zhí)行,任務(wù)間隔2秒,服務(wù)啟動(dòng)15秒后關(guān)閉
依賴
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>任務(wù)調(diào)度
@Component
//SpringBoot服務(wù)啟動(dòng)執(zhí)行
public class CronScheduler implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
JobDetail build = JobBuilder.newJob(QuartzJob.class)
.withIdentity("myJob", "group1")
.build();
Date date = new Date();
long startTime = date.getTime() + 5000;
long endTime = date.getTime() + 15000;
CronTrigger c = TriggerBuilder.newTrigger()
.startAt(new Date(startTime))
.endAt(new Date(endTime))
.withIdentity("CronTrigger1", "t1")
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
.build();
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//設(shè)置調(diào)度的job和trigger
scheduler.scheduleJob(build, c);
//開啟調(diào)度
scheduler.start();
//暫停,可以重新啟動(dòng)
//scheduler.standby();
//停止調(diào)度程序觸發(fā)觸發(fā)器,并清除與調(diào)度程序關(guān)聯(lián)的所有資源
//scheduler.shushutdown();
}
}具體執(zhí)行的任務(wù)
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(new Date());
}
}
到此這篇關(guān)于springboot實(shí)現(xiàn)定時(shí)任務(wù)的四種方式小結(jié)的文章就介紹到這了,更多相關(guān)springboot 定時(shí)任務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring的@RequestParam對(duì)象綁定方式
這篇文章主要介紹了Spring的@RequestParam對(duì)象綁定方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring Aop 如何獲取參數(shù)名參數(shù)值
這篇文章主要介紹了Spring Aop 如何獲取參數(shù)名參數(shù)值的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
利用openoffice+jodconverter-code-3.0-bate4實(shí)現(xiàn)ppt轉(zhuǎn)圖片
這篇文章主要為大家詳細(xì)介紹了利用openoffice+jodconverter-code-3.0-bate4實(shí)現(xiàn)ppt轉(zhuǎn)圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
JAVA 16位ID生成工具類含16位不重復(fù)的隨機(jī)數(shù)數(shù)字+大小寫
這篇文章主要介紹了JAVA 16位ID生成工具類含16位不重復(fù)的隨機(jī)數(shù)數(shù)字+大小寫,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
springboot @ComponentScan注解原理解析
這篇文章主要介紹了springboot @ComponentScan注解原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02

