在Spring定時任務@Scheduled註解使用方式淺窺這篇文章裏面說起過,spring的定時任務默認是單線程的,他在某些場景下會形成堵塞,那麼若是咱們想讓每個任務都起一條線程去執行呢?spring
咱們可使用Spring的@Async註解十分容易的實現多線程的任務執行。
測試代碼:segmentfault
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
結果日誌多線程
2018-06-12 16:02:42.005 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task run 2018-06-12 16:02:42.007 [taskExecutor-94] INFO service.task.testTask -taskExecutor-94===task end 2018-06-12 16:02:44.004 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task run 2018-06-12 16:02:44.015 [taskExecutor-95] INFO service.task.testTask -taskExecutor-95===task end 2018-06-12 16:02:46.004 [taskExecutor-99] INFO service.task.testTask -taskExecutor-99===task run 2018-06-12 16:02:46.014 [taskExecutor-96] INFO service.task.testTask -taskExecutor-96===task end 2018-06-12 16:02:48.004 [taskExecutor-100] INFO service.task.testTask -taskExecutor-100===task run 2018-06-12 16:02:48.010 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task end 2018-06-12 16:02:50.005 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 16:02:50.008 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task end 2018-06-12 16:02:52.006 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run
截取部分結果日誌咱們能夠看到,在上一個任務6s的執行時間內,下一個任務並無等待上一個任務結束,而是在任務開始時間直接開啓了一條新的線程進行執行。
仔細觀察結果咱們還能夠發現,每條結果都是一條新的線程,直到100時,才又從第一條線程開始。這是由於在默認不作配置的狀況下,@Async所使用的線程池容量爲100,每次須要的時候都會從中拿出一條,直到用完,纔會等待以前的線程釋放,不會再本身擴容。
下面咱們稍稍改下代碼來證明一下:異步
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(300*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
此次我讓任務執行的時間等於300s,大於100條線程總間隔時間來耗盡線程池中的線程。
結果日誌測試
2018-06-12 16:26:44.411 [taskExecutor-93] INFO service.task.testTask -taskExecutor-93===task run 2018-06-12 16:26:46.853 [taskExecutor-94] INFO service.task.testTask -taskExecutor-94===task run 2018-06-12 16:26:48.008 [taskExecutor-95] INFO service.task.testTask -taskExecutor-95===task run 2018-06-12 16:26:50.008 [taskExecutor-96] INFO service.task.testTask -taskExecutor-96===task run 2018-06-12 16:26:52.006 [taskExecutor-97] INFO service.task.testTask -taskExecutor-97===task run 2018-06-12 16:26:54.008 [taskExecutor-98] INFO service.task.testTask -taskExecutor-98===task run 2018-06-12 16:26:56.006 [taskExecutor-99] INFO service.task.testTask -taskExecutor-99===task run 2018-06-12 16:26:58.005 [taskExecutor-100] INFO service.task.testTask -taskExecutor-100===task run 2018-06-12 16:28:40.142 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task end 2018-06-12 16:28:40.149 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 16:28:42.117 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task end 2018-06-12 16:28:42.121 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run 2018-06-12 16:28:44.253 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task end 2018-06-12 16:28:44.257 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task run 2018-06-12 16:28:46.027 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task end 2018-06-12 16:28:46.031 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task run
經過日誌咱們能夠看到,再第100條線程也開始執行任務後,沒有新的線程再被建立,而是等待有線程執行完後,再開始執行本次任務。線程
雖然上面的方式已經解決了咱們的問題,可是總以爲不太好,有時候咱們須要異步執行任務,可是又不須要這麼多的線程的時候,咱們可使用下面的配置來設置線程池的大小
配置文件:日誌
<task:annotation-driven scheduler="testScheduler" /> <!-- 配置任務線程池和線程池大小 --> <task:scheduler id="testScheduler" pool-size="6" />
測試代碼:code
@Scheduled(cron = "0/2 * * * * ?") @Async public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(6*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
結果日誌:視頻
2018-06-12 18:32:56.032 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task run 2018-06-12 18:32:58.007 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task run 2018-06-12 18:33:00.005 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task run 2018-06-12 18:33:02.008 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task run 2018-06-12 18:33:02.036 [taskExecutor-1] INFO service.task.testTask -taskExecutor-1===task end 2018-06-12 18:33:04.327 [taskExecutor-2] INFO service.task.testTask -taskExecutor-2===task end 2018-06-12 18:33:04.328 [taskExecutor-5] INFO service.task.testTask -taskExecutor-5===task run 2018-06-12 18:33:06.007 [taskExecutor-6] INFO service.task.testTask -taskExecutor-6===task run 2018-06-12 18:33:06.010 [taskExecutor-3] INFO service.task.testTask -taskExecutor-3===task end 2018-06-12 18:33:08.459 [taskExecutor-4] INFO service.task.testTask -taskExecutor-4===task end 2018-06-12 18:33:08.460 [taskExecutor-7] INFO service.task.testTask -taskExecutor-7===task run 2018-06-12 18:33:10.011 [taskExecutor-8] INFO service.task.testTask -taskExecutor-8===task run 2018-06-12 18:33:10.332 [taskExecutor-5] INFO service.task.testTask -taskExecutor-5===task end 2018-06-12 18:33:12.005 [taskExecutor-9] INFO service.task.testTask -taskExecutor-9===task run 2018-06-12 18:33:12.012 [taskExecutor-6] INFO service.task.testTask -taskExecutor-6===task end 2018-06-12 18:33:14.904 [taskExecutor-10] INFO service.task.testTask -taskExecutor-10===task run 2018-06-12 18:33:14.904 [taskExecutor-7] INFO service.task.testTask -taskExecutor-7===task end
結果和咱們預料的並不同啊,線程數超過了6,這是什麼緣由呢?get
其實若是咱們在使用@Async時想使用配置好的線程池,須要爲@Async註解添加value屬性來制定所用的線程池。
修改後的代碼
@Scheduled(cron = "0/2 * * * * ?") @Async("testScheduler") public void doTask() throws InterruptedException { logger.info(Thread.currentThread().getName()+"===task run"); Thread.sleep(30*1_000); logger.info(Thread.currentThread().getName()+"===task end"); }
結果日誌:
2018-06-12 18:54:42.035 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task run 2018-06-12 18:54:44.010 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task run 2018-06-12 18:54:46.007 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task run 2018-06-12 18:54:48.007 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task run 2018-06-12 18:54:50.005 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task run 2018-06-12 18:54:52.021 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task run 2018-06-12 18:55:12.039 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task end 2018-06-12 18:55:12.044 [testScheduler-3] INFO service.task.testTask -testScheduler-3===task run 2018-06-12 18:55:14.016 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task end 2018-06-12 18:55:14.022 [testScheduler-2] INFO service.task.testTask -testScheduler-2===task run 2018-06-12 18:55:16.289 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task end 2018-06-12 18:55:16.297 [testScheduler-1] INFO service.task.testTask -testScheduler-1===task run 2018-06-12 18:55:18.289 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task end 2018-06-12 18:55:18.293 [testScheduler-5] INFO service.task.testTask -testScheduler-5===task run 2018-06-12 18:55:20.009 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task end 2018-06-12 18:55:20.014 [testScheduler-4] INFO service.task.testTask -testScheduler-4===task run 2018-06-12 18:55:22.165 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task end 2018-06-12 18:55:22.172 [testScheduler-6] INFO service.task.testTask -testScheduler-6===task run
此次結果和咱們的預計是同樣的了,在初始的6條線程使用完畢之後就會等待以前的線程釋放啦,同時也能夠看到線程池名是咱們設置的線程池。
若有錯誤,歡迎留言指正,謝謝你們!
提供一些優秀的IT視頻資料,可免費下載!如須要請查看https://www.592xuexi.com