本文內容已經同步更新到 Github:https://github.com/Snailclimb... ,歡迎 star。java
不少時候咱們都須要爲系統創建一個定時任務來幫咱們作一些事情,SpringBoot 已經幫咱們實現好了一個,咱們只須要直接使用便可,固然你也能夠不用 SpringBoot 自帶的定時任務,整合 Quartz 不少時候也是一個不錯的選擇。git
本文不涉及 SpringBoot 整合 Quartz 的內容,只演示瞭如何使用 SpringBoot 自帶的實現定時任務的方式。github
咱們只須要 SpringBoot 項目最基本的依賴便可,因此這裏就不貼配置文件了。面試
咱們使用 @Scheduled
註解就能很方便地建立一個定時任務,下面的代碼中涵蓋了 @Scheduled
的常見用法,包括:固定速率執行、固定延遲執行、初始延遲執行、使用 Cron 表達式執行定時任務。spring
Cron 表達式: 主要用於定時做業(定時任務)系統定義執行時間或執行頻率的表達式,很是厲害,你能夠經過 Cron 表達式進行設置定時任務天天或者每月何時執行等等操做。推薦一個在線Cron表達式生成器:http://cron.qqe2.com/springboot
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
看下面的運行任務示意圖應該很好理解了。spa
若是咱們將這個方法改成並行運行,運行結果就大相徑庭了。
@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」 便可免費無套路獲取。