Spring多線程通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)
一、前言
技術(shù)的入門大多比較簡單,把別人的代碼復(fù)制過來,刪刪改改,基本也就能實(shí)現(xiàn)個(gè)功能,查看個(gè)API大概也就知道如何實(shí)現(xiàn)幾個(gè)功能,但是,如果對一項(xiàng)技術(shù)了解的足夠深入,就要知道一個(gè)技術(shù)的優(yōu)缺點(diǎn),以及他存在的問題,這些就需要大量的時(shí)間及思考,疾風(fēng)知?jiǎng)挪?,只有足夠了解才能臨危不懼,才能在如疾風(fēng)般強(qiáng)勁的bug來臨時(shí)微微一笑,絕對不倒!
二、定時(shí)任務(wù)調(diào)度注解@Scheduled
這個(gè)注解是spring定時(shí)任務(wù)中的主角,他包含幾種類型:
- @Scheduled(fixedDelay = 2000)
- @Scheduled(fixedRate = 2000)
- @Scheduled(initialDelay = 1000, fixedDelay = 2000)
- @Scheduled(cron = "*/5 * * * * *")
使用過定時(shí)任務(wù)的童鞋應(yīng)該都是使用過以上集中注解,現(xiàn)在簡單介紹一下
- @Scheduled(fixedDelay = 2000) 等上一個(gè)任務(wù)執(zhí)行完2s后執(zhí)行
- @Scheduled(fixedRate = 2000) 從上一個(gè)任務(wù)開始后的2s,下一個(gè)任務(wù)進(jìn)行執(zhí)行
- @Scheduled(initialDelay = 1000, fixedDelay = 2000) 方法不會立即執(zhí)行 要等initialDelay后再執(zhí)行
- @Scheduled(cron = "*/5 * * * * *") 選定時(shí)間進(jìn)行執(zhí)行
下面重點(diǎn)說一下 @Scheduled(fixedRate = 2000)
他的說明是從上一個(gè)任務(wù)開始后的2s,下一個(gè)任務(wù)進(jìn)行執(zhí)行,但是真的如此嗎? 我們來驗(yàn)證一下
創(chuàng)建一個(gè)定時(shí)任務(wù)類,及定時(shí)任務(wù)方法:
/** * Spring的定時(shí)任務(wù) */ @Component @EnableScheduling public class ScheduleJob { @Autowired private TaskService taskService; /** * 和上一個(gè)方法的開始和下一個(gè)方法的開始固定是2s * 這種方法適合任務(wù)之間是獨(dú)立的 */ @Scheduled(fixedRate = 2000) public void fixedRateTaskR() { taskService.sayHello("fixedRate"); }
創(chuàng)建接口:
public interface TaskService { void sayHello(String type); }
具體實(shí)現(xiàn)類:
@Override public void sayHello(String type) { try { long startTime = System.currentTimeMillis() / 1000; System.out.println(type + " => " + startTime + " - 任務(wù)開始"); System.out.println(type + " => " + "任務(wù)執(zhí)行中"); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } }
我在執(zhí)行的任務(wù)線程進(jìn)行延時(shí)操作,每次執(zhí)行都會休眠5s,如果每兩秒執(zhí)行一次那么,方法的間隔時(shí)間打印出來就是2s,我們執(zhí)行下,
看下結(jié)果:
fixedRate => 1632646194 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646197 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646199 - 任務(wù)開始
結(jié)果很明顯是間隔了5s執(zhí)行一次,而不是2s,說明要等上一個(gè)任務(wù)執(zhí)行完下一個(gè)任務(wù)才會執(zhí)行,哇塞不哇塞! 既然存在這樣的問題,那如果我就要不等上一個(gè)任務(wù)執(zhí)行完,就是要2s執(zhí)行一次能不能干! 當(dāng)然能干!現(xiàn)在就干!
三、使用@Async實(shí)現(xiàn)異步調(diào)度
建立spring線程池
/** * @Description spring線程池配置類 */ @EnableAsync @Configuration public class SendMsgThreadPoolConfig { @Bean("schedule") public Executor schduleTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(2); executor.setMaxPoolSize(2); executor.setQueueCapacity(100); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("schedule-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }
為異步調(diào)度方法指定線程池
@Override @Async("schedule") public void sayHello(String type) { try { long startTime = System.currentTimeMillis() / 1000; System.out.println(type + " => " + startTime + " - 任務(wù)開始"); System.out.println(type + " => " + "任務(wù)執(zhí)行中"); Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); } }
我們再執(zhí)行以下,看下輸出結(jié)果:
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646666 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646668 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646671 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632646673 - 任務(wù)開始
看下控制臺,現(xiàn)在的時(shí)間間隔就是2s,2s,3s
,小伙伴可能就會覺得奇怪了,為啥出現(xiàn)了3s的間隔,這是咋回事,這是因?yàn)槲覀儎?chuàng)建的線程池,我們線程池的核心線程和最大線程數(shù)都是2個(gè),每兩秒執(zhí)行一次,前4s兩個(gè)線程就被占滿了,第三個(gè)任務(wù)執(zhí)行時(shí),要進(jìn)行等待,因?yàn)榈谝粋€(gè)任務(wù)線程的休眠時(shí)間是5s,那么第三個(gè)任務(wù)線程在等待1s后會執(zhí)行,這就是間隔3s的原因,驗(yàn)證一下,將線程數(shù)修改為3個(gè)。
看下控制臺輸出:
fixedRate => 1632647147 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632647149 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
fixedRate => 1632647151 - 任務(wù)開始
fixedRate => 任務(wù)執(zhí)行中
這是執(zhí)行時(shí)間間隔就為2s了。
到此這篇關(guān)于Spring多線程通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)的文章就介紹到這了,更多相關(guān)Spring定時(shí)任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)計(jì)模式之觀察者模式(Observer模式)
這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式(Observer模式),文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04Java實(shí)現(xiàn)雙保險(xiǎn)線程的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)雙保險(xiǎn)線程的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12獲取Spring的上下文環(huán)境ApplicationContext的最簡單方式
這篇文章主要介紹了獲取Spring的上下文環(huán)境ApplicationContext的最簡單方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作
這篇文章主要介紹了SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄
這篇文章主要介紹了Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04springboot2整合redis使用lettuce連接池的方法(解決lettuce連接池?zé)o效問題)
這篇文章主要介紹了springboot2整合redis使用lettuce連接池(解決lettuce連接池?zé)o效問題),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12