定時任務作為一種系統調度工具,在一些需要有定時作業的系統中應用廣泛,如每逢某個時間點統計數據、在將來某個時刻執行某些動作...定時任務在主流開發語言均提供相應的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. 線程實現
利用線程可以設定休眠時間的方式可以實現簡單的定時任務邏輯。
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任務。使用這種方式可以讓你的程序按照某一個頻度執行。
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類的定時任務類,歸根到底也是基于線程的調度實現的。
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依賴
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-quartz</artifactid>
</dependency>
配置
@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();
}
}
測試
public class QuartzTest extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext){
System.out.println("quartz執行一次定時任務 ");
}
}
5. 使用Scheduled注解
@Scheduled是spring為定時任務而生的一個注解,查看注解的源碼:
@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注解來實現定時任務。
開啟定時任務支持
@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());
}
}
使用
@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 * ?