本文內容已經同步更新到 Github:github.com/Snailclimb/… ,歡迎 star。java
不少時候咱們都須要爲系統創建一個定時任務來幫咱們作一些事情,SpringBoot 已經幫咱們實現好了一個,咱們只須要直接使用便可,固然你也能夠不用 SpringBoot 自帶的定時任務,整合 Quartz 不少時候也是一個不錯的選擇。git
本文不涉及 SpringBoot 整合 Quartz 的內容,只演示瞭如何使用 SpringBoot 自帶的實現定時任務的方式。github
咱們只須要 SpringBoot 項目最基本的依賴便可,因此這裏就不貼配置文件了。面試
咱們使用 @Scheduled
註解就能很方便地建立一個定時任務,下面的代碼中涵蓋了 @Scheduled
的常見用法,包括:固定速率執行、固定延遲執行、初始延遲執行、使用 Cron 表達式執行定時任務。spring
Cron 表達式: 主要用於定時做業(定時任務)系統定義執行時間或執行頻率的表達式,很是厲害,你能夠經過 Cron 表達式進行設置定時任務天天或者每月何時執行等等操做。springboot
推薦一個在線Cron表達式生成器:cron.qqe2.com/bash
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/** * @author shuang.kou */
@Component
public class ScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
/** * fixedRate:固定速率執行。每5秒執行一次。 */
@Scheduled(fixedRate = 5000)
public void reportCurrentTimeWithFixedRate() {
log.info("Current Thread : {}", Thread.currentThread().getName());
log.info("Fixed Rate Task : The time is now {}", dateFormat.format(new Date()));
}
/** * fixedDelay:固定延遲執行。距離上一次調用成功後2秒才執。 */
@Scheduled(fixedDelay = 2000)
public void reportCurrentTimeWithFixedDelay() {
try {
TimeUnit.SECONDS.sleep(3);
log.info("Fixed Delay Task : The time is now {}", dateFormat.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/** * initialDelay:初始延遲。任務的第一次執行將延遲5秒,而後將以5秒的固定間隔執行。 */
@Scheduled(initialDelay = 5000, fixedRate = 5000)
public void reportCurrentTimeWithInitialDelay() {
log.info("Fixed Rate Task with Initial Delay : The time is now {}", dateFormat.format(new Date()));
}
/** * cron:使用Cron表達式。 每分鐘的1,2秒運行 */
@Scheduled(cron = "1-2 * * * * ? ")
public void reportCurrentTimeWithCronExpression() {
log.info("Cron Expression: The time is now {}", dateFormat.format(new Date()));
}
}
複製代碼
關於 fixedRate 這裏其實有個坑,假如咱們有這樣一種狀況:咱們某個方法的定時器設定的固定速率是每5秒執行一次。這個方法如今要執行下面四個任務,四個任務的耗時是:6 s、6s、 2s、 3s,請問這些任務默認狀況下(單線程)將如何被執行?ide
咱們寫一段簡單的程序驗證:學習
private static final Logger log = LoggerFactory.getLogger(AsyncScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
private List<Integer> index = Arrays.asList(6, 6, 2, 3);
int i = 0;
@Scheduled(fixedRate = 5000)
public void reportCurrentTimeWithFixedRate() {
if (i == 0) {
log.info("Start time is {}", dateFormat.format(new Date()));
}
if (i < 5) {
try {
TimeUnit.SECONDS.sleep(index.get(i));
log.info("Fixed Rate Task : The time is now {}", dateFormat.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
複製代碼
運行程序輸出以下:ui
Start time is 20:58:33
Fixed Rate Task : The time is now 20:58:39
Fixed Rate Task : The time is now 20:58:45
Fixed Rate Task : The time is now 20:58:47
Fixed Rate Task : The time is now 20:58:51
複製代碼
看下面的運行任務示意圖應該很好理解了。
若是咱們將這個方法改成並行運行,運行結果就大相徑庭了。
@EnableScheduling
註解在 SpringBoot 中咱們只須要在啓動類上加上@EnableScheduling
即可以啓動定時任務了。
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
複製代碼
默認狀況下,@Scheduled
任務都在Spring建立的大小爲1的默認線程池中執行,你能夠經過在加了@Scheduled
註解的方法里加上下面這段代碼來驗證。
logger.info("Current Thread : {}", Thread.currentThread().getName());
複製代碼
你會發現加上上面這段代碼的定時任務,每次運行都會輸出:
Current Thread : scheduling-1
複製代碼
若是咱們須要自定義線程池執行話只須要新加一個實現SchedulingConfigurer
接口的 configureTasks
的類便可,這個類須要加上 @Configuration
註解。
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-");
threadPoolTaskScheduler.initialize();
scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
複製代碼
經過上面的驗證的方式輸出當前線程的名字會改變。
若是你想要你的代碼並行執行的話,還能夠經過@EnableAsync
和 @Async
這兩個註解實現
@Component
@EnableAsync
public class AsyncScheduledTasks {
private static final Logger log = LoggerFactory.getLogger(AsyncScheduledTasks.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
/** * fixedDelay:固定延遲執行。距離上一次調用成功後2秒才執。 */
//@Async
@Scheduled(fixedDelay = 2000)
public void reportCurrentTimeWithFixedDelay() {
try {
TimeUnit.SECONDS.sleep(3);
log.info("Fixed Delay Task : The time is now {}", dateFormat.format(new Date()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
複製代碼
運行程序輸出以下,reportCurrentTimeWithFixedDelay()
方法會每5秒執行一次,由於咱們說過了@Scheduled
任務都在Spring建立的大小爲1的默認線程池中執行。
Current Thread : scheduling-1
Fixed Delay Task : The time is now 14:24:23
Current Thread : scheduling-1
Fixed Delay Task : The time is now 14:24:28
Current Thread : scheduling-1
Fixed Delay Task : The time is now 14:24:33
複製代碼
reportCurrentTimeWithFixedDelay()
方法上加上 @Async
註解後輸出以下,reportCurrentTimeWithFixedDelay()
方法會每 2 秒執行一次。
Current Thread : task-1
Fixed Delay Task : The time is now 14:27:32
Current Thread : task-2
Fixed Delay Task : The time is now 14:27:34
Current Thread : task-3
Fixed Delay Task : The time is now 14:27:36
複製代碼
若是你們想要實時關注我更新的文章以及分享的乾貨的話,能夠關注個人公衆號。
《Java面試突擊》: 由本文檔衍生的專爲面試而生的《Java面試突擊》V2.0 PDF 版本公衆號後臺回覆 "Java面試突擊" 便可免費領取!
Java工程師必備學習資源: 一些Java工程師經常使用學習資源公衆號後臺回覆關鍵字 「1」 便可免費無套路獲取。