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

SpringBoot定時任務多實例互斥執(zhí)行的完整指南

 更新時間:2026年01月26日 08:33:31   作者:風象南  
Spring Boot 的 @Scheduled 寫定時任務很方便,但多實例部署時有個問題,同一個定時任務會在每臺機器上都觸發(fā)執(zhí)行,下面我們就來看看如何解決吧

Spring Boot 的 @Scheduled 寫定時任務很方便,但多實例部署時有個問題:同一個定時任務會在每臺機器上都觸發(fā)執(zhí)行。

比如部署了兩臺應用服務器,凌晨 2 點的數(shù)據(jù)統(tǒng)計任務會同時跑兩遍,數(shù)據(jù)重復、文件重復生成。

解決這個問題通常有幾種思路。

常見方案

方案一:單機執(zhí)行

只在一臺指定的機器上跑任務:

@Scheduled(cron = "0 0 2 * * ?")
public void scheduledTask() {
    String hostname = InetAddress.getLocalHost().getHostName();
    if (!"app-server-01".equals(hostname)) {
        return;
    }
    // do something
}

問題很明顯:那臺機器掛了,任務就不執(zhí)行了。

方案二:Redis 分布式鎖

用 Redis 的 SETNX 實現(xiàn)互斥(或者Redission):

@Scheduled(cron = "0 0 2 * * ?")
public void scheduledTask() {
    Boolean locked = stringRedisTemplate.opsForValue()
        .setIfAbsent("task:data-sync", "1", 10, TimeUnit.MINUTES);
    if (Boolean.FALSE.equals(locked)) {
        return;
    }
    try {
        // do something
    } finally {
        stringRedisTemplate.delete("task:data-sync");
    }
}

能用,但每個任務都要寫一遍加鎖釋放邏輯,而且需要項目里有 Redis。

ShedLock 方案

ShedLock 是一個專門解決定時任務重復執(zhí)行問題的框架,支持多種存儲后端(數(shù)據(jù)庫、Redis、MongoDB 等)。

核心思路:在存儲層記錄每個任務的鎖狀態(tài),任務執(zhí)行前先搶鎖,搶到了才執(zhí)行。

集成步驟

1. 添加依賴

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>4.42.0</version>
</dependency>
<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>4.42.0</version>
</dependency>

2. 創(chuàng)建鎖表

CREATE TABLE shedlock (
    name VARCHAR(64) NOT NULL,
    lock_until TIMESTAMP(3) NOT NULL,
    locked_at TIMESTAMP(3) NOT NULL,
    locked_by VARCHAR(255) NOT NULL,
    PRIMARY KEY (name)
);

3. 配置 LockProvider

@Configuration
@EnableSchedulerLock(defaultLockAtMostFor = "10m")
public class ShedLockConfig {

    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(
            JdbcTemplateLockProvider.Configuration.builder()
                .withDataSource(dataSource)
                .withTableName("shedlock")
                .build()
        );
    }
}

4. 給定時任務加注解

@Scheduled(cron = "0 0 2 * * ?")
@SchedulerLock(name = "dataSyncTask", lockAtMostFor = "5m")
public void syncData() {
    // do something
}

完成。多臺服務器部署時,只有搶到鎖的那臺會執(zhí)行任務。

注解參數(shù)說明

@SchedulerLock 有幾個關鍵參數(shù):

name:鎖名稱,相同 name 的任務會互斥執(zhí)行。建議用任務名來命名,保持唯一。

lockAtMostFor:鎖的最大持有時間。

這是為了防止任務執(zhí)行過程中機器宕機,導致鎖永遠不釋放。比如設置 5m,即使任務執(zhí)行超時,鎖也會在 5 分鐘后自動過期。

一般按任務預期執(zhí)行時間的 2 倍左右設置,留些余量。

lockAtLeastFor:鎖的最小持有時間。

這是為了防止任務執(zhí)行太快,鎖立即釋放被其他機器搶到。

比如定時任務每分鐘執(zhí)行一次,任務 5 秒就跑完了。如果沒有這個參數(shù),其他機器可能會在同一分鐘內(nèi)再次搶到鎖執(zhí)行。

這種情況下可以設置 lockAtLeastFor = "1m",確保鎖保持到下一分鐘。

實現(xiàn)原理

ShedLock 的實現(xiàn)邏輯不復雜。

任務執(zhí)行前,會向數(shù)據(jù)庫插入或更新鎖記錄:

INSERT INTO shedlock (name, lock_until, locked_at, locked_by)
VALUES ('dataSyncTask', '2025-01-25 02:05:00', NOW(), '192.168.1.10')
ON DUPLICATE KEY UPDATE
  lock_until = '2025-01-25 02:05:00',
  locked_at = NOW(),
  locked_by = '192.168.1.10'
WHERE lock_until < NOW();

關鍵是最后的 WHERE lock_until < NOW() 條件:

  • 如果當前鎖已過期,UPDATE 成功,搶到鎖
  • 如果當前鎖未過期,UPDATE 影響行數(shù)為 0,搶鎖失敗,任務不執(zhí)行

任務執(zhí)行完成后不需要主動釋放鎖,等待 lock_until 時間到期即可。

適用場景

ShedLock 的定位很明確:專門為定時任務設計的分布式鎖框架。

適合

  • 定時任務需要互斥執(zhí)行,避免重復
  • 希望用注解方式簡化鎖的代碼邏輯
  • 需要自動鎖過期機制,防止死鎖

不適合

  • 高并發(fā)搶鎖的業(yè)務場景(比如秒殺、庫存扣減),ShedLock 不是為此設計
  • 需要可重入鎖、讀寫鎖等復雜特性
  • 需要精確控制鎖獲取和釋放時機的業(yè)務邏輯

ShedLock 和通用分布式鎖是互補關系,不是替代關系。如果你的業(yè)務代碼里需要手動加鎖解鎖,用 Redisson 或手動實現(xiàn) Redis SETNX 更合適。但如果只是為了解決定時任務重復執(zhí)行的問題,ShedLock 是更簡潔的方案。

幾個注意事項

1. 存儲后端選擇

本文演示用的是 JDBC 方式(基于數(shù)據(jù)庫表)。ShedLock 還支持 Redis、MongoDB、ZooKeeper、Hazelcast 等多種存儲后端,根據(jù)項目現(xiàn)有技術棧選擇即可。

2. 表名自定義(數(shù)據(jù)庫存儲時)

如果用 JDBC 作為存儲后端,默認表名是 shedlock,可以按需修改: 3. 機器標識

locked_by 字段記錄是哪臺機器拿到的鎖,默認是主機名??梢宰远x成更有意義的標識:

.withLockedByValue("app-" + getServerIp())

4. 主從/多數(shù)據(jù)源場景(數(shù)據(jù)庫存儲時)

如果項目有多個數(shù)據(jù)源,確保 ShedLock 用的是主庫,避免主從延遲導致的鎖問題。

總結

ShedLock 是一個專門為定時任務設計的分布式鎖框架:

  • 優(yōu)點:注解式使用、集成簡單、自動鎖過期、支持多種存儲后端
  • 局限性:只適用于定時任務場景,不適用于通用業(yè)務加鎖

和手動寫 Redis 分布式鎖相比,ShedLock 把定時任務鎖的邏輯抽象出來了,代碼更簡潔。但如果你需要的是通用業(yè)務鎖,還是用 Redisson 或手寫 SETNX 更合適。

以上就是SpringBoot定時任務多實例互斥執(zhí)行的完整指南的詳細內(nèi)容,更多關于SpringBoot定時任務的資料請關注腳本之家其它相關文章!

相關文章

  • Java中Thread類基本用法詳解

    Java中Thread類基本用法詳解

    Java中的Thread類是用于創(chuàng)建和管理線程的類,Thread類提供了許多方法來管理線程,包括啟動線程、中斷線程、暫停線程等,下面這篇文章主要給大家介紹了關于Java中Thread類基本用法的相關資料,需要的朋友可以參考下
    2023-06-06
  • Jedis出現(xiàn)connection timeout問題解決方法(JedisPool連接池使用實例)

    Jedis出現(xiàn)connection timeout問題解決方法(JedisPool連接池使用實例)

    這篇文章主要介紹了Jedis出現(xiàn)connection timeout問題解決方法,使用Jedis的JedisPool連接池解決了這個問題,需要的朋友可以參考下
    2014-05-05
  • springboot集成mybatisPlus+多數(shù)據(jù)源的實現(xiàn)示例

    springboot集成mybatisPlus+多數(shù)據(jù)源的實現(xiàn)示例

    這篇文章主要介紹了springboot集成mybatisPlus+多數(shù)據(jù)源的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-12-12
  • Mybatis如何實現(xiàn)延遲加載及緩存

    Mybatis如何實現(xiàn)延遲加載及緩存

    這篇文章主要介紹了Mybatis如何實現(xiàn)延遲加載及緩存,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • 通過Java實現(xiàn)反向代理集群服務的平滑分配

    通過Java實現(xiàn)反向代理集群服務的平滑分配

    這篇文章主要介紹了如何通過Java語言,自己編寫的平滑加權輪詢算法,結合線程池和Socket?網(wǎng)絡編程等,并實現(xiàn)反向代理集群服務的平滑分配,需要的可以參考一下
    2022-04-04
  • Springboot中如何通過yml為實體類注入屬性

    Springboot中如何通過yml為實體類注入屬性

    這篇文章主要介紹了Springboot中如何通過yml為實體類注入屬性,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • idea?maven依賴引入失效無法正常導入依賴問題的解決方法

    idea?maven依賴引入失效無法正常導入依賴問題的解決方法

    有時候idea導入一個新項目,或者pom文件修改(新增)了依賴,pom文件和代碼會報紅,提示依賴包不存在,下面這篇文章主要給大家介紹了關于idea?maven依賴引入失效無法正常導入依賴問題的解決方法,需要的朋友可以參考下
    2023-04-04
  • Java Swing組件BoxLayout布局用法示例

    Java Swing組件BoxLayout布局用法示例

    這篇文章主要介紹了Java Swing組件BoxLayout布局用法,結合實例形式分析了Swing使用BoxLayout容器進行布局的相關方法與操作技巧,需要的朋友可以參考下
    2017-11-11
  • 利用Spring框架為自己的校園卡充值(推薦)

    利用Spring框架為自己的校園卡充值(推薦)

    這篇文章主要介紹了利用Spring框架為自己的校園卡充值,本次實驗主要運用了Spring的控制反轉(IOC)和依賴注入(DI)等知識,通過利用Spring框架編寫Java程序,實現(xiàn)學生卡的單次充值,如需對學生卡進行多次充值,可將部分代碼修改即可實現(xiàn),需要的朋友可以參考下
    2022-10-10
  • 關于IDEA MybatisX插件的使用小技巧

    關于IDEA MybatisX插件的使用小技巧

    這篇文章主要介紹了關于MybatisX插件的使用小技巧,MybatisX是IDEA的一款第三方插件,可以極大地提升我們的開發(fā)效率,一起來看看吧
    2023-03-03

最新評論

昌图县| 马关县| 敦化市| 翼城县| 呼和浩特市| 九台市| 沂水县| 安图县| 拉孜县| 霍邱县| 拉萨市| 凤冈县| 集安市| 常德市| 太仆寺旗| 宜君县| 大新县| 略阳县| 长丰县| 马山县| 特克斯县| 天门市| 江华| 浪卡子县| 德州市| 沂南县| 民县| 微博| 建平县| 津南区| 城固县| 三台县| 都江堰市| 涿鹿县| 东台市| 宝清县| 长子县| 黄龙县| 慈利县| 岳西县| 兰坪|