最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

spring調(diào)度注解@Scheduled方式(含分布式)

 更新時(shí)間:2024年11月20日 17:19:25   作者:sjzwangxufeng  
文章介紹了Java中任務(wù)調(diào)度的幾種常見方法,包括JDK原生的Timer、ScheduledThreadPoolExecutor和Spring的@Scheduled注解,文章還討論了如何在分布式環(huán)境中實(shí)現(xiàn)任務(wù)調(diào)度,并介紹了一些開源的分布式任務(wù)調(diào)度解決方案,如Quartz和XXL-JOB

簡述

任務(wù)調(diào)度就是在給定的時(shí)間或固定頻率,執(zhí)行業(yè)務(wù)邏輯,是比較常見的功能需求。

解決方案有jdk原生的Timer、ScheduledThreadPoolExecutor等,這些類常適用于一些內(nèi)嵌的業(yè)務(wù)邏輯場景。

本文主要介紹注解@Scheduled,以上都是單進(jìn)程解決方案,經(jīng)過適當(dāng)改造,也可以適用于分布式場景,可以滿足大多數(shù)調(diào)度業(yè)務(wù)場景,具體實(shí)現(xiàn)思路下面會做簡單敘述。

配置

開啟

項(xiàng)目開啟調(diào)度功能,需要先添加注解@EnableScheduling,否則調(diào)度注解@Scheduled就不起作用。

線程池

既然是任務(wù)運(yùn)行,就會涉及線程處理,如果有不同類型的任務(wù),也會出現(xiàn)并行處理,對線程的合理管理,就離不開線程池,以下是線程池配置整理

(1) 不配置(默認(rèn))

如果不做任何配置處理,spring-boot 會默認(rèn)自動構(gòu)建一個(gè)ThreadPoolTaskScheduler線程池類bean, 來管理這些運(yùn)行任務(wù)的線程,默認(rèn)線程池的具體參數(shù)值,可參考TaskSchedulingProperties類定義的默認(rèn)值,如下:

// pool
private int size = 1;

// thread
private String threadNamePrefix = "scheduling-";

通過源碼知道,這個(gè)默認(rèn)線程池,內(nèi)部實(shí)際由jdk的ScheduledThreadPoolExecutor類處理,該類采用無限容量隊(duì)列,這也就限制了它的最大線程數(shù)不會超過1個(gè),如果有耗時(shí)的并行任務(wù),就不能滿足要求,通常情況下,需要根據(jù)業(yè)務(wù)場景重新配置這些參數(shù)。

(2) spring配置

spring-boot項(xiàng)目已提供TaskSchedulingAutoConfiguration類,由它自動加載線程池配置參數(shù),并構(gòu)建ThreadPoolTaskScheduler線程池類bean,以下是約定的配置項(xiàng):

spring:
  task:
    scheduling:
      threadNamePrefix: my-scheduler-task-
      pool:
        size: 3

線程池的大小,依據(jù)配置調(diào)度注解@Scheduled任務(wù)的數(shù)量,原則上有幾種任務(wù)就需要幾個(gè)線程,否則就會出現(xiàn)相互影響,長耗時(shí)任務(wù)占用線程,導(dǎo)致短耗時(shí)任務(wù)不能正常運(yùn)行。

(3) java代碼配置

調(diào)度任務(wù)不像@Async異常處理,它只有一個(gè)線程池,一般情況不用這種配置方式,以下是簡單例子。

@Configuration
public class ScheduleConfig {
	
    private static final String THREAD_NAME_PREFIX = "my-scheduler-task-";	

    @Bean("myTaskScheduler")
    public ThreadPoolTaskScheduler getThreadPoolTaskScheduler() {
    	ThreadPoolTaskScheduler result = new ThreadPoolTaskScheduler();
    	result.setThreadNamePrefix(THREAD_NAME_PREFIX);
    	result.setPoolSize(3);
    	return result;
    }
}

調(diào)度規(guī)則

@Scheduled包含參數(shù):

  • cron:定時(shí)任務(wù),按cron表達(dá)式規(guī)則,定時(shí)運(yùn)行任務(wù),例如,每5分鐘運(yùn)行一次: 0/5 * * * * ?
  • fixedDelay:按固定間隔執(zhí)行,就是兩個(gè)相鄰任務(wù),前一個(gè)任務(wù)結(jié)束到下一個(gè)任務(wù)開始的間隔時(shí)間,單位: 毫秒。
  • fixedRate:按固定頻率執(zhí)行任務(wù),單位: 毫秒。
  • initialDelay:系統(tǒng)啟動后,延時(shí)多長時(shí)間運(yùn)行第一次任務(wù),單位: 毫秒。

其中:cron, fixedDelay, fixedRate 配置參數(shù),只能三選一。

分布式

現(xiàn)在系統(tǒng)大多在分布式環(huán)境部署,就需要考慮多實(shí)例部署如何協(xié)調(diào)執(zhí)行任務(wù)問題,以下是常見的解決方案,以及個(gè)人的思考。

第三方

目前第三方的開源方案,有早期比較經(jīng)典的Quartz,近幾年版本迭代不太活躍,也有后起之秀XXL-JOB 版本迭代比較活躍,也是目前很多公司推崇的解決方案,對任務(wù)的管理、監(jiān)控、日志等功能比較齊全,可以參考其官方,這里就不再多述。

自處理

盡管上面開源的第三方解決方案,已經(jīng)足夠成熟、完善,但相對來說,還是有些重,對于一些系統(tǒng)規(guī)模不是很大,一些簡單的任務(wù)調(diào)度需求,完全可以進(jìn)行簡單改造來滿足這些任務(wù)調(diào)度功能。

盡管簡單,它一樣可以很實(shí)用、很健壯,以下是2種借助redis的處理思路。

(1) @Scheduled為主,redis為輔

通過@Scheduled注解的調(diào)度任務(wù),在分布式環(huán)境運(yùn)行,一個(gè)明顯的問題,就是同一個(gè)任務(wù),可能會在多個(gè)機(jī)器同時(shí)并發(fā)執(zhí)行,如何避免,很自然就想到通過redis分布式鎖處理,來避免任務(wù)并發(fā)執(zhí)行,鎖定時(shí)間可以設(shè)置0.75個(gè)執(zhí)行周期,以下是偽碼

	@Scheduled(fixedDelay = 60000, initialDelay = 1000)
	public void task1() {
		
		// 鎖定
		boolean isLock = redisLock.lock("my-task-1", 60000 * 0.75);
		if (!isLock) return;
		
		// 任務(wù)邏輯
		doSomething();
	}

可以看出,這種方式,任務(wù)周期誤差比較大,比較粗糙,特點(diǎn)就是邏輯簡單,適用于精度要求較低的場景。

(2) redis為主,@Scheduled為輔

由于通過@Scheduled來配置執(zhí)行周期,在分布式環(huán)境,很難保證周期的精度,這時(shí)候可以把@Scheduled僅作為嘗試申請執(zhí)行的一個(gè)定時(shí)掃描任務(wù),真實(shí)的執(zhí)行周期由redis的過期時(shí)間來管理,這種方式,任務(wù)周期精度就會好很多,以下是偽碼:

按固定頻率執(zhí)行:

	/*
	 * redis為主,@Scheduled為輔(按固定頻率執(zhí)行任務(wù))
	 * 
	 * note:
	 * a. @Scheduled注解中fixedDelay,該參數(shù)僅作為嘗試申請執(zhí)行任務(wù), 通??梢栽O(shè)置小些。
	 * b. 任務(wù)執(zhí)行周期或間隔,值為redisLock鎖定的時(shí)間。
	 * 
	 */
	@Scheduled(fixedDelay = 5000, initialDelay = 1000)
	public void task2() {
		
		// 鎖定
		boolean isLock = redisLock.lock("my-task-2", 真實(shí)任務(wù)周期);
		if (!isLock) return;
		
		// 任務(wù)邏輯
		doSomething();
		
	}

按固定間隔執(zhí)行:

	/*
	 * redis為主,@Scheduled為輔(按固定間隔執(zhí)行)
	 * 
	 * note:
	 * a. @Scheduled注解中fixedDelay,該參數(shù)僅作為嘗試申請執(zhí)行任務(wù), 通??梢栽O(shè)置小些。
	 * b. 任務(wù)執(zhí)行周期或間隔,值為redisLock鎖定的時(shí)間。
	 * 
	 */
	@Scheduled(fixedDelay = 5000, initialDelay = 1000)
	public void task3() {
		
		// 鎖定1: 避免任務(wù)并行
		boolean isLock = redisLock.lock("my-task-3", 真實(shí)任務(wù)間隔);
		if (!isLock) return;
		
		// 任務(wù)邏輯
		doSomething();
		
		// 鎖定2: 間隔時(shí)間
		redisLock.expire("my-task-3", 真實(shí)任務(wù)間隔);
		
	}

按cron表達(dá)式執(zhí)行:可通過注解@Scheduled參數(shù)fixedDelay,來調(diào)整周期精度。

	/*
	 * redis為主,@Scheduled為輔(cron表達(dá))
	 * 
	 * note:
	 * a. @Scheduled注解中fixedDelay,該參數(shù)僅作為嘗試申請執(zhí)行任務(wù), 通常可以設(shè)置小些。
	 * b. 任務(wù)執(zhí)行周期或間隔,值為redisLock鎖定的時(shí)間。
	 * c. 由CronHelper解析cron表達(dá)式,計(jì)算下一次運(yùn)行間隔時(shí)間
	 */
	@Scheduled(fixedDelay = 5000, initialDelay = 1000)
	public void task4()  {
		
		// 鎖定
		boolean isLock = redisLock.lock("my-task-4", CronHelper.getNextDelayTime());
		if (!isLock) return;
		
		// 任務(wù)邏輯
		doSomething();		
	}

以上只偽碼,可以看出改造成本比較少,也足夠靈活,其中RedisLock可以參考前面整理的文章:分布式鎖-java,至于CronHelper類,網(wǎng)上應(yīng)該有類似資源,也不妨自己實(shí)現(xiàn)一下,應(yīng)該比排序算法有趣的多。

再就是任務(wù)的運(yùn)行,不能保證負(fù)載均衡,如果的確有這方面需求,通過redis隊(duì)列也可以實(shí)現(xiàn),邏輯也不會太復(fù)雜。

個(gè)人認(rèn)為:

這種自處理方式,借助redis還是可以保障它的高可用性、并發(fā)性能,它的主要缺陷,就是代碼語義不夠清晰,在維護(hù)上,容易受注解@Scheduled定時(shí)參數(shù)影響,實(shí)際業(yè)務(wù)場景,盡量封裝一下,提高可讀性。

常見問題

(1) 線程池的大小,建議幾種任務(wù)就幾個(gè)線程,多了也浪費(fèi),如果太小,任務(wù)耗時(shí)長時(shí),就會出現(xiàn)任務(wù)間干擾。

(2) 如果任務(wù)有嚴(yán)格的并行限制,可以通過分布式鎖防護(hù)一下。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • springboot基于注解實(shí)現(xiàn)去重表消息防止重復(fù)消費(fèi)

    springboot基于注解實(shí)現(xiàn)去重表消息防止重復(fù)消費(fèi)

    本文主要介紹了springboot基于注解實(shí)現(xiàn)去重表消息防止重復(fù)消費(fèi),通過記錄消息ID、使用分布式鎖和設(shè)置過期時(shí)間,可以確保消息只會被處理一次,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-05-05
  • Java中字符串根據(jù)寬度(像素)換行的問題

    Java中字符串根據(jù)寬度(像素)換行的問題

    這篇文章主要介紹了Java中字符串根據(jù)寬度(像素)換行的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java并發(fā)編程線程間通訊實(shí)現(xiàn)過程詳解

    Java并發(fā)編程線程間通訊實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了Java并發(fā)編程線程間通訊實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • Java多線程編程:線程的原理和使用安全

    Java多線程編程:線程的原理和使用安全

    文章主要介紹了線程的基本概念、線程和進(jìn)程的區(qū)別、線程的創(chuàng)建方法、線程的常見方法與屬性、線程的安全問題等,線程是程序執(zhí)行流的最小單位,可以并發(fā)執(zhí)行并共享數(shù)據(jù),線程的生命周期狀態(tài)包括新建、就緒、運(yùn)行、阻塞、死亡等
    2026-05-05
  • springboot自定義攔截器的方法

    springboot自定義攔截器的方法

    這篇文章主要為大家詳細(xì)介紹了springboot自定義攔截器的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • ElasticSearch?深度分頁示例解析

    ElasticSearch?深度分頁示例解析

    這篇文章主要為大家介紹了ElasticSearch?深度分頁示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Mybatis之a(chǎn)ssociation和collection用法

    Mybatis之a(chǎn)ssociation和collection用法

    這篇文章主要介紹了Mybatis之a(chǎn)ssociation和collection用法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java 中的Printstream介紹_動力節(jié)點(diǎn)Java學(xué)院整理

    Java 中的Printstream介紹_動力節(jié)點(diǎn)Java學(xué)院整理

    PrintStream 是打印輸出流,它繼承于FilterOutputStream。接下來通過本文給大家介紹Java 中的Printstream,需要的朋友參考下吧
    2017-05-05
  • JAVA純代碼導(dǎo)出PDF文件實(shí)現(xiàn)方式

    JAVA純代碼導(dǎo)出PDF文件實(shí)現(xiàn)方式

    本文介紹了作者通過突發(fā)奇想發(fā)布了生成PDF的博客,最初,作者通過將Word文件轉(zhuǎn)換為PDF文件實(shí)現(xiàn)導(dǎo)出PDF功能,但效果不盡如人意,后來,作者嘗試直接生成PDF文件,并修復(fù)了生成PDF時(shí)出現(xiàn)的小瑕疵,通過導(dǎo)入依賴、下載接口和下載方法的實(shí)現(xiàn)
    2025-01-01
  • Springboot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)代碼實(shí)例

    Springboot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)代碼實(shí)例

    這篇文章主要介紹了Springboot集成Quartz實(shí)現(xiàn)定時(shí)任務(wù)代碼實(shí)例,任務(wù)是有可能并發(fā)執(zhí)行的,若Scheduler直接使用Job,就會存在對同一個(gè)Job實(shí)例并發(fā)訪問的問題,而JobDetail?&?Job方式,Scheduler都會根據(jù)JobDetail創(chuàng)建一個(gè)新的Job實(shí)例,這樣就可以規(guī)避并發(fā)訪問問題
    2023-09-09

最新評論

胶南市| 儋州市| 南陵县| 甘泉县| 盐池县| 扎兰屯市| 台中市| 淮阳县| 灵石县| 崇仁县| 山阳县| 麻城市| 文登市| 娱乐| 洪洞县| 巴彦县| 太仆寺旗| 大石桥市| 大石桥市| 遂昌县| 彰武县| 太仆寺旗| 白水县| 常德市| 塔河县| 崇信县| 娱乐| 揭东县| 永新县| 神木县| 东阿县| 三河市| 留坝县| 永济市| 寻乌县| 贵德县| 都昌县| 隆回县| 应城市| 伊川县| 上犹县|