摘要:定時任務高級使用篇前面一篇博文之定時任務基本使用篇介紹了環境下,定時任務的簡單使用姿勢,也留了一些問題,這一篇則希望能針對這些問題給個答案定時任務進階篇問題小結前面一篇博文,拋出了下面的幾個問題,接下來則圍繞問題進行分析一個項目中有多個定時
Spring定時任務高級使用篇
前面一篇博文 《Spring之定時任務基本使用篇》 介紹了Spring環境下,定時任務的簡單使用姿勢,也留了一些問題,這一篇則希望能針對這些問題給個答案
I. 定時任務進階篇 1. 問題小結前面一篇博文,拋出了下面的幾個問題,接下來則圍繞問題進行分析
一個項目中有多個定時任務時,他們是并行執行的還是串行執行的?
如果默認是串行的
那么有相同的crond表達式的定時任務之間,有先后順序么?
某個任務的阻塞是否會影響后面的任務?
如果需要他們并行執行,可以怎么做?
如果是并發執行的
是新創建線程還是采用線程池來復用呢?
在并發執行時,假設有個每秒執行一次的任務,但是它執行一次消耗的時間大于1s時,這個任務的表現時怎樣的呢?不斷地新增線程來執行還是等執行完畢之后再執行下一次的呢?
2. 多定時任務的串并行分析如何確認一個項目中的多個定時任務是串行執行還是并發執行呢?要想驗證這個功能,最好的法子就是寫個testcase,比如定義兩個定時任務,在其中一個任務中寫個死循環,看另外一個任務是否會正常執行
@Scheduled(cron = "0/1 * * * * ?") public void sc1() throws InterruptedException { System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis()); while (true) { Thread.sleep(5000); } } @Scheduled(cron = "0/1 * * * * ?") public void sc2() { System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis()); }
首先我們分析的是 sc1和sc2這兩個任務的執行是串行還是并行的,暫時先不考慮 sc1 調用時阻塞,下一秒是否是開新的線程再調用sc1
若串行:則sc1打印一次,sc2可能打印0或者1次
若并行:sc1打印一次,sc2打印n多次
實際運行,GIF圖演示如下
上圖的結果,印證了默認的情況下,多個定時任務時串行執行的;如果一個任務出現阻塞,其他的任務都會受到影響
3. 定時任務執行的優先級既然是順序執行的,那么優先級怎么定?每次都是固定的,還是隨機的呢?
要驗證上面的方法,也容易,同樣兩個任務,看他們的輸出是否會亂掉,如果每次都是任務1打印完再打印任務2,那就是固定優先級的;否則每次調度時,順序不好說
測試代碼如下
@Scheduled(cron = "0/1 * * * * ?") public void sc1() { System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis()); } @Scheduled(cron = "0/1 * * * * ?") public void sc2() { System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis()); }
實測結果如下
從輸出得出結論:順序是串掉的,并沒有表現出明顯的優先級關系
4. 并行調度接下來的問題就是我希望這些任務可以并發執行,可以實現么?
當然是可以,用起來也比較簡單,首先是在Application上添加注解@EnableAsync,開啟異步調用,然后再計劃任務上加上@Async注解即可,一個簡單的demo如下
@EnableAsync @EnableScheduling @SpringBootApplication public class QuickMediaApplication { public static void main(String[] args) { SpringApplication.run(QuickMediaApplication.class, args); } @Scheduled(cron = "0/1 * * * * ?") @Async public void sc1() { System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis()); } }
上面執行之后,查看輸出(異步調度時,理論上線程名應該不一樣)
從上面的輸出,可以簡單的推理,每次調度上面的任務都是新開了一個線程來做的,所以如果在定時任務中寫了死循環,是否會導致無限線程,最后整個進程崩掉?
額外提一句,linux系統下單進程的線程數是有上線的,查看命令為:
ulimit -u
在測試之前,先看下上面的正常任務執行,如下面的動圖,線程數并沒有夸張的長法
接下來換成死循環的調度方式,實際測試如下,線程數蹭蹭的上漲
所以使用默認的異步調用方式,并不是一個好注意,說不準就被玩死了自己都不知道,那么可以用自己的線程池來管理這些異步任務么?
5. 自定義線程池用自定義的線程池來取代默認線程管理方式,無疑是一個更加安全和靈活的方式,使用起來也并不麻煩,和平常創建線程池的套路沒什么區別,要在Spring生態中使用,就把它搞成bean即可
直接借助Spring的線程池ThreadPoolTaskExecutor
@Bean public AsyncTaskExecutor asyncTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setThreadNamePrefix("yhh-schedule-"); executor.setMaxPoolSize(10); executor.setCorePoolSize(3); executor.setQueueCapacity(0); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); return executor; } @Scheduled(cron = "0/1 * * * * ?") @Async public void sc1() throws InterruptedException { System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis()); while (true) { Thread.sleep(1000 * 5); } }
實際演示的結果如下,最多10個線程,再提交的任務直接丟棄
簡單說一下,用自定義線程池的好處:
合理的分配線程池參數
拒絕策略的選擇也比較有意思(可以按照自己的想法來處理"負載"的任務)
線程池命名,對于以后問題排查,會有很大的幫助
6. 小結本來這篇博文在昨天即8月2號就應該寫完的,結果晚上生產環境下除了點問題,解決線上故障之后就比較晚了,留到了今天,哎,拖延癥也是要不得。。。
下面小結Spring中定時任務的幾個知識點
默認所有的定時任務都是串行調度的,一個線程,且即便crond完全相同的兩個任務先后順序也沒法保證(具體原因需要源碼分析,看下這塊是怎么支持)
使用@Async注解可以使定時任務異步調度;但是需要開啟配置,在啟動類上添加 @EnableAsync 注解
開啟并發執行時,推薦用自定義的線程池來替代默認的,理由見上面
II. 其他 0. 相關《Spring之定時任務基本使用篇》
1. 一灰灰Blog: https://liuyueyi.github.io/he...一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛
2. 聲明盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
微博地址: 小灰灰Blog
QQ: 一灰灰/3302797840
3. 掃描關注小灰灰Blog&公眾號
知識星球
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/76625.html
摘要:表示起始時間開始觸發,然后每隔固定時間觸發一次如在域使用則意味著分鐘觸發一次,而,等分別觸發一次表示列出枚舉值值。 showImg(https://segmentfault.com/img/remote/1460000015852353); 文章鏈接:https://liuyueyi.github.io/hexblog/2018/08/01/180801-Spring之定時任務基本使用...
本文來自網絡一些博客的整理(包括gong1208的博客 dary1715的博客) 1、簡介 這個系列介紹Spring框架實現定時任務的兩種方式以及一些高級的用法,包括: 1、使用Quartz,這是一個功能比較強大的的調度器,可以讓你的程序在指定時間執行,也可以按照某一個頻度執行,配置起來稍顯復雜,稍后會詳細介紹。 2、Spring3.0以后自帶的task,可以將它看成一個輕量級的Quartz,而且...
摘要:當前時間打印當前時間定時任務觸發,操作多個添加數據,事務中任一異常,都可以正常導致數據回滾。當前時間當前時間添加微服務啟動類注解式配置定時任務,不支持任務調度。 SpringCloud(第 046 篇)注解式Schedule配置定時任務,不支持任務調度 - 一、大致介紹 1、很多時候我們需要隔一定的時間去執行某個任務,為了實現這樣的需求通常最普通的方式就是利用多線程來實現; 2、但是有...
摘要:在定時器接口的方法中我們可以發現一個方法接受接口,而也是一個接口,抽象了觸發任務執行的觸發器。更常用的一個觸發器是,它使用表達式指定何時執行任務。配置定時任務首先看看配置。配置提供了命名空間,讓配置定時任務非常簡單。 本文參考自Spring官方文檔 34. Task Execution and Scheduling。 在程序中常常有定時任務的需求,例如每隔一周生成一次報表、每個月月末清...
摘要:添加任務成功運行任務名稱添加定時任務服務定時任務服務。觸發器計劃列表添加測試任務類測試任務類被任務調度后執行該任務類。聲明一個靜態變量保存添加啟動類簡單微服務,不支持分布式。 SpringCloud(第 009 篇)簡單 Quartz 微服務,不支持分布式 - 一、大致介紹 1、本章節僅僅只是為了測試 Quartz 在微服務中的使用情況; 2、其實若只是簡單的實現任務調用而言的話,Sp...
閱讀 2376·2021-09-30 09:47
閱讀 1367·2021-09-28 09:35
閱讀 3237·2021-09-22 15:57
閱讀 2485·2021-09-22 14:59
閱讀 3634·2021-09-07 10:25
閱讀 3069·2021-09-03 10:48
閱讀 3035·2021-08-26 14:14
閱讀 933·2019-08-30 15:55