本文旨在用通俗的語言講述枯燥的知識
定時任務作為一種系統調度工具,在一些需要有定時作業的系統中應用廣泛,如每逢某個時間點統計數據、在將來某個時刻執行某些動作...定時任務在主流開發語言均提供相應的api供開發者調用,在java中,實現定時任務有很多種方式,原生的方式實現一個完整定時任務需要由timer、timertask兩個類,timer是定時器類,用來按計劃開啟后臺線程執行指定任務,timertask一個抽象類,它的子類代表一個可以被timer計劃的任務。除此之外,還可以用scheduledexecutorservice類或者使用第三方jar庫quartz,其中quartz是一個優秀的定時任務框架,發展至今已經非常成熟,以致后來其他的定時任務框架的核心思想或底層大多源于quartz。
springboot作為java的一種開發框架,在springboot項目中實現定時任務不僅可以使用java提供的原生方式,還可以使用springboot提供的定時任務api,下面,小編把java原生和springboot所有的實現定時任務的方式做一個整合。
文章提綱:
1、使用線程
2、使用timer類
3、使用scheduledexecutorservice類
4、使用quartz
5、使用spring的@scheduled注解
6、cron表達式
1. 線程實現
利用線程可以設定休眠時間的方式可以實現簡單的定時任務邏輯。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static void main(string[] args){ //定時任務間隔時間 int sleeptime= 2 * 1000 ; new thread( new runnable() { @override public void run() { while ( true ){ try { system.out.println( "thread方式執行一次定時任務" ); //線程休眠規定時間 thread.sleep(sleeptime); } catch (interruptedexception e) { e.printstacktrace(); } } } }).start(); } |
2. timer類
timer類允許調度一個timertask任務。使用這種方式可以讓你的程序按照某一個頻度執行。
1
2
3
4
5
6
7
8
9
10
|
public static void main(string[] args){ int sleeptime= 2 * 1000 ; timertask timertask = new timertask() { @override public void run() { system.out.println( "timer方式執行一次定時任務" ); } }; new timer().schedule(timertask, 1 ,sleeptime); } |
3. scheduledexecutorservice類
scheduledexecutorservice,是基于線程池設計的定時任務類,每個調度任務都會分配到線程池中的一個線程去執行,也就是說,任務是并發執行,互不影響。
因此,基于scheduledexecutorservice類的定時任務類,歸根到底也是基于線程的調度實現的。
1
2
3
4
5
6
7
8
9
10
11
12
|
public static void main(string[] args){ int sleeptime= 2 * 1000 ; scheduledexecutorservice scheduledexecutor = executors.newsinglethreadscheduledexecutor(); scheduledexecutor.scheduleatfixedrate( new runnable() { @override public void run() { system.out.println( "scheduledexecutorservice方式執行一次定時任務" ); } } , 1 ,sleeptime, timeunit.seconds); } |
4. 整合quartz
quartz是一個完全由java編寫的開源作業調度框架,為在 java 應用程序中進行作業調度提供了簡單卻強大的機制,要理解它的使用方式,需要先理解它的幾個核心概念:
job: 表示一個工作,要執行的具體內容。此接口中只有一個方法,如下:
void execute(jobexecutioncontext context)
- jobdetail: 表示一個具體的可執行的調度程序,job 是這個可執行程調度程序所要執行的內容,另外 jobdetail 還包含了這個任務調度的方案和策略。
- trigger: 代表一個調度參數的配置,什么時候去調。
- scheduler: 代表一個調度容器,一個調度容器中可以注冊多個 jobdetail 和trigger。當 trigger 與 jobdetail 組合,就可以被 scheduler 容器調度了。
有了這些概念之后,我們就可以把quartz整合到我們的springboot項目中了。
引入quartz依賴
1
2
3
4
|
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-quartz</artifactid> </dependency> |
配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@configuration public class quartzconfig { @bean public jobdetail quartzdetail(){ return jobbuilder.newjob(quartztest. class ).withidentity( "quartztest" ).storedurably().build(); } @bean public simpletrigger quartztrigger(){ simpleschedulebuilder schedulebuilder = simpleschedulebuilder.simpleschedule() .withintervalinseconds( 10 ) .repeatforever(); return triggerbuilder.newtrigger().forjob(quartzdetail()) .withidentity( "quartztest" ) .withschedule(schedulebuilder) .build(); } } |
測試
1
2
3
4
5
6
|
public class quartztest extends quartzjobbean { @override protected void executeinternal(jobexecutioncontext jobexecutioncontext){ system.out.println( "quartz執行一次定時任務 " ); } } |
5. 使用scheduled注解
@scheduled是spring為定時任務而生的一個注解,查看注解的源碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@target ({elementtype.method, elementtype.annotation_type}) @retention (retentionpolicy.runtime) @documented @repeatable (schedules. class ) public @interface scheduled { //cron表達式 string cron() default "" ; //接收一個java.util.timezone#id。 string zone() default "" ; //上一次執行完畢時間點之后多長時間再執行 long fixeddelay() default - 1 ; //支持占位符形式的字符串類型的fixeddelay string fixeddelaystring() default "" ; //上一次開始執行時間點之后多長時間再執行 long fixedrate() default - 1 ; //支持占位符形式的字符串類型的fixedratestring string fixedratestring() default "" ; //第一次延遲多長時間后再執行 long initialdelay() default - 1 ; //支持占位符形式的字符串類型的initialdelay string initialdelaystring() default "" ; } |
可以看出:scheduled注解中的參數用來設置“定時”動作,通常情況下,比較常用的參數是cron(),這意味著我們需要學會一些cron表達式相關的語法,但由于內容較多,篇幅較長,在這里暫不鋪開講解,我們把cron語法相關放到文章最后,在此先講解如何用scheduled注解來實現定時任務。
開啟定時任務支持
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@springbootapplication /** * 開啟定時任務支持 */ @enablescheduling public class testapplication extends springbootservletinitializer { public static void main(string[] args) { springapplication.run(testapplication. class , args); } @override protected springapplicationbuilder configure(springapplicationbuilder builder) { return builder.sources( this .getclass()); } } |
使用
1
2
3
4
5
6
7
8
9
10
11
|
@component public class scheduledtest { private logger logger = loggerfactory.getlogger(scheduledtest. class ); /** * 每15秒執行一次定時任務 */ @scheduled (cron = "0/15 * * * * ? " ) public void testcron(){ logger.info( "scheduled 執行一次定時任務" ); } } |
6. cron表達式
cron表達式是一個字符串其語法為:
[秒] [分] [小時] [日] [月] [周] [年]
其中[年]為非必填項,因此通常cron表達式通常由6或7部分內容組成,內容的取值為數字或者一些cron表達式約定的特殊字符,這些特殊字符稱為“通配符”,每一個通配符分別代指一種值。cron表達式可以用這樣的表格來表示:
順序 | 取值范圍 | 特殊字符串范圍 |
---|---|---|
秒 | 0~60 | , - * / |
分 | 0-60 | , - * / |
時 | 0-23 | , - * / |
日 | 1-31 | , - * / |
月 | 1-12 / jan-dec | , - * ? / l w |
周 | 1-7 / sun-sat | , - * ? / l # |
年(可省略) | 1970-2099 | , - * / |
其中通配符的解釋以及作用如下:
通配符 | 代表的值 | 解釋 |
---|---|---|
* | 所有值 | 如:時字段為*,代表每小時都觸發 |
? | 不指定值 | 如:周字段為?,代表表達式不關心是周幾 |
- | 區間 | 如:時字段設置2-5,代表2,3,4,5點鐘時都觸發 |
, | 多個值 | 如:時字段設置2,3,5,代表2,3,5點都會觸發 |
/ | 遞增值 | 如:時字段設置0/2,代表每兩個小時觸發,時字段設置 2/5,代表從2時開始每隔5小時觸發一次 |
l | 最后值 | 如:日字段設置l,代表本月最后一天 |
w | 最近工作日 | 如:在日字段設置13w,代表沒約13日最近的那個工作日觸發一次 |
# | 序號 | 如:在周字段設置5#2,代表每月的第二個周五 |
示例:
每2秒執行一次:0/5 ?
每5分鐘執行一次:0 0/5 * ?
1分、12分、45分執行一次:0 1,12,45 * ?
每天23點59分59秒執行一次:59 59 23 ?
每月15號凌晨3點執行一次:0 0 3 15 * ?
每月最后一天12點執行一次:0 0 12 l * ?
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://segmentfault.com/a/1190000018145078