Spring多線程通過@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)
一、前言
技術(shù)的入門大多比較簡(jiǎn)單,把別人的代碼復(fù)制過來,刪刪改改,基本也就能實(shí)現(xiàn)個(gè)功能,查看個(gè)API大概也就知道如何實(shí)現(xiàn)幾個(gè)功能,但是,如果對(duì)一項(xiàng)技術(shù)了解的足夠深入,就要知道一個(gè)技術(shù)的優(yōu)缺點(diǎn),以及他存在的問題,這些就需要大量的時(shí)間及思考,疾風(fēng)知?jiǎng)挪?,只有足夠了解才能臨危不懼,才能在如疾風(fēng)般強(qiáng)勁的bug來臨時(shí)微微一笑,絕對(duì)不倒!
二、定時(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)在簡(jiǎ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) 方法不會(huì)立即執(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í)行都會(huì)休眠5s,如果每?jī)擅雸?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ù)才會(huì)執(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();
}
}我們?cè)賵?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ù)開始
看下控制臺(tái),現(xiàn)在的時(shí)間間隔就是2s,2s,3s,小伙伴可能就會(huì)覺得奇怪了,為啥出現(xiàn)了3s的間隔,這是咋回事,這是因?yàn)槲覀儎?chuàng)建的線程池,我們線程池的核心線程和最大線程數(shù)都是2個(gè),每?jī)擅雸?zhí)行一次,前4s兩個(gè)線程就被占滿了,第三個(gè)任務(wù)執(zhí)行時(shí),要進(jìn)行等待,因?yàn)榈谝粋€(gè)任務(wù)線程的休眠時(shí)間是5s,那么第三個(gè)任務(wù)線程在等待1s后會(huì)執(zhí)行,這就是間隔3s的原因,驗(yàn)證一下,將線程數(shù)修改為3個(gè)。
看下控制臺(tái)輸出:
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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)計(jì)模式之觀察者模式(Observer模式)
這篇文章主要介紹了Java設(shè)計(jì)模式之觀察者模式(Observer模式),文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
Java實(shí)現(xiàn)雙保險(xiǎn)線程的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)雙保險(xiǎn)線程的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12
獲取Spring的上下文環(huán)境ApplicationContext的最簡(jiǎn)單方式
這篇文章主要介紹了獲取Spring的上下文環(huán)境ApplicationContext的最簡(jiǎn)單方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作
這篇文章主要介紹了SpringBoot 關(guān)于Feign的超時(shí)時(shí)間配置操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄
這篇文章主要介紹了Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
springboot2整合redis使用lettuce連接池的方法(解決lettuce連接池?zé)o效問題)
這篇文章主要介紹了springboot2整合redis使用lettuce連接池(解決lettuce連接池?zé)o效問題),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12

