簡單示例
導入依賴
springBoot已經默認集成了定時任務的依賴,只需要引入基本的依賴就可以使用定時任務。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
啟動類配置
在啟動類中需要加入@EnableScheduling注解,意思是開啟定時任務。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* Author: YaoQi
* Date: 2018/9/28 21:37
* Description: springBoot schedule
*/
@SpringBootApplication
@EnableScheduling
public class ScheduleApp {
public static void main(String[] args) {
SpringApplication.run(ScheduleApp.class, args);
}
}
定時任務Demo
寫一個定時任務demo,每秒種打印一次日志,並打印當前時間驗證當前任務執行周期。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
/**
* Author: YaoQi
* Date: 2018/9/28 21:40
* Description: Scheduled Task
*/
@Service
public class ScheduleTask {
private static final Logger logger = LoggerFactory.getLogger(ScheduleTask.class);
@Scheduled(cron = "*/1 * * * * ?")
public void execute() {
logger.info("print word.");
logger.info(String.valueOf(System.currentTimeMillis()));
}
}
運行結果:
示例分析
從上圖的結果中看:該任務基本是每秒種執行一次,如果不手動停止,程序會一直執行下去,並且從日志中看,這個任務的執行周期是1s左右,剛好和設置的cron表達式一致;並且執行這個任務的線程一直是poll-1-thread-1這個線程。這就意味着,這個定時任務啟動是由單獨的一個線程去執行的。
這時候,可能會有幾個問題:
如果任務執行的時間比執行周期要短,這個任務會怎么執行?
如果有多個任務執行,還會是一個線程去執行這個任務嗎?
首先驗證第一個問題,當任務執行的時間比執行周期短時,任務的執行情況。
@Scheduled(cron = "*/1 * * * * ?")
public void execute() {
logger.info("print word.");
logger.info(String.valueOf(System.currentTimeMillis()));
try {
Thread.sleep(6000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
執行結果:每次任務的執行時間間隔為7秒,並且是同一個線程在執行。
如果有多個任務執行,任務的執行情況。
@Scheduled(cron = "*/1 * * * * ?")
public void execute() {
logger.info("print word.");
try {
Thread.sleep(6000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Scheduled(cron = "*/1 * * * * ?")
public void execute1() {
logger.info(String.valueOf(System.currentTimeMillis()));
logger.info("write message.");
}
執行結果:
執行結果:第二個每秒執行一次的任務的並沒有安裝設定的執行周期執行,運行結果並沒有達到預期。並且兩個任務都是由同一個線程去運行。
多任務模式
示例分析中問題2的原因就是執行多個任務並不是多個線程執行,導致執行第一個任務時,第二個任務進入等待狀態。springBoot中提供了多線程運行定時任務的方式。
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3));
}
}
增加一個配置類,設置線程池,並設置線程池大小,這里的線程池大小就仁者見仁了,和你程序中的任務的個數有關系,也和機器的核數有關系。
通過配置線程池就能讓每個任務獨立執行,不受其他任務的影響,因為是在不同的線程中執行的,但如果涉及到公共資源就另當別論了。
執行結果:
配置執行周期
上述中的執行周期都是以cron表達式定義的,這種方式最靈活,但是上文中的表達式都寫到代碼中去了,不便於修改,這里提供一種配置方式,直接用表達式獲取yml中的配置信息。
scheduleTask:
cron1: "*/1 * * * * ?"
cron2: "*/1 * * * * ?"
在yml中添加cron的配置信息。然后在Java注解中可以直接獲取。
@Scheduled(cron = "${scheduleTask.cron2}")
public void execute1() {
logger.info(String.valueOf(System.currentTimeMillis()));
logger.info("write message.");
}