Java中實(shí)現(xiàn)分布式定時任務(wù)的方法
定時器Scheduler在平時使用比較頻繁,在springboot中,配置好@Scheduled和@EnableScheduling之后,定時器就能正常執(zhí)行,實(shí)現(xiàn)定時任務(wù)的功能。
但是在這樣的情況下:如果開發(fā)的服務(wù)需要水平部署實(shí)現(xiàn)負(fù)載均衡,那么定時任務(wù)就會同時在多個服務(wù)實(shí)例上運(yùn)行,那么一方面,可能由于定時任務(wù)的邏輯處理需要訪問公共資源從而造成并發(fā)問題;另一方面,就算沒有并發(fā)問題,那么一個同樣的任務(wù)多個服務(wù)實(shí)例同時執(zhí)行,也會造成資源的浪費(fèi)。因此需要一種機(jī)制來保證多個服務(wù)實(shí)例之間的定時任務(wù)正常、合理地執(zhí)行。
本文以shedlock為例,來實(shí)現(xiàn)分布式定時任務(wù)的控制。
ShedLock可以保證多個同樣的定時任務(wù)在多個服務(wù)實(shí)例之間最多只執(zhí)行一次,是一個在分布式環(huán)境中保證定時任務(wù)合理執(zhí)行的框架,我們可以叫它分布式定時任務(wù)鎖。
ShedLock的實(shí)現(xiàn)原理是采用公共存儲實(shí)現(xiàn)的鎖機(jī)制,使得同一時間點(diǎn)只有第一個執(zhí)行定時任務(wù)的服務(wù)實(shí)例能執(zhí)行成功,并在公共存儲中存儲"我正在執(zhí)行任務(wù),從什么時候(預(yù)計(jì))執(zhí)行到什么時候",其他服務(wù)實(shí)例執(zhí)行時如果發(fā)現(xiàn)任務(wù)正在執(zhí)行,則直接跳過本次執(zhí)行,從而保證同一時間一個任務(wù)只被執(zhí)行一次。
ShedLock的公共存儲目前支持的有:MonogoDynamoDBJdbcTemplateZooKeeper (using Curator)Redis (using Spring RedisConnectionFactory)Redis (using Jedis)Hazelcast第一步引入依賴
<!-- shedlock start --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.11.1</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>4.11.1</version> </dependency> <!-- shedlock end -->
第二步添加配置類
import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import javax.annotation.Resource; import javax.sql.DataSource; import java.util.TimeZone; /** * @descrition shedlock配置類 * @since 2021-01-10 22:39 */ @Configuration public class ShedLockConfig { @Resource private DataSource dataSource; /** * @description * @date 2021/1/10 22:39 */ @Bean public LockProvider lockProvider() { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .withTimeZone(TimeZone.getTimeZone("GMT+8")) .build() ); } }
第三步,添加公共存儲,前面我們說過shedlock支持多種公共存儲作為鎖,本文我們以mysql為例
CREATE TABLE shedlock ( NAME VARCHAR ( 64 ) NOT NULL, lock_until TIMESTAMP ( 3 ) NOT NULL, locked_at TIMESTAMP ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ), locked_by VARCHAR ( 255 ) NOT NULL, PRIMARY KEY ( NAME ) );
第四步,添加具體任務(wù)類
import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; /** * @author shane * @date 2021/1/10 23:39 */ @Slf4j @Component public class TestJob { /** * @description 每隔1min打印一次 * @date 2021/1/10 23:39 */ @Scheduled(cron = "0 0/1 * * * ?") // lockAtMostFor為鎖默認(rèn)持有時間,會覆蓋啟動類中的默認(rèn)持有時間 @SchedulerLock(name = "demo", lockAtMostFor = "70m") public void print() throws InterruptedException { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設(shè)置日期格式 log.warn("當(dāng)前時間:"+df.format(new Date())); } }
接著,我們復(fù)制一份代碼,分別啟動兩個實(shí)例來看結(jié)果數(shù)據(jù)庫記錄
@SchedulerLock注解參數(shù)說明name:定時任務(wù)的名字,就是數(shù)據(jù)庫中的內(nèi)個主鍵
lockAtMostFor:鎖的最大時間單位為毫秒
lockAtLeastFor:鎖的最小時間單位為毫秒
對了,還有啟動類的配置
@SpringBootApplication @MapperScan("com.example.test.mapper") @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "10m") // 默認(rèn)的鎖的時間 public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
參考出處:
https://www.jianshu.com/p/941416645606
shedlock的github地址:https://github.com/lukas-krecan/ShedLock
到此這篇關(guān)于Java中實(shí)現(xiàn)分布式定時任務(wù)的方法的文章就介紹到這了,更多相關(guān)java分布式定時任務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Security賬戶與密碼驗(yàn)證實(shí)現(xiàn)過程
這篇文章主要介紹了Spring Security賬戶與密碼驗(yàn)證實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-03-03Java單線程程序?qū)崿F(xiàn)實(shí)現(xiàn)簡單聊天功能
這篇文章主要介紹了Java單線程程序?qū)崿F(xiàn)實(shí)現(xiàn)簡單聊天功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10詳解java中反射機(jī)制(含數(shù)組參數(shù))
這篇文章主要介紹了詳解java中反射機(jī)制(含數(shù)組參數(shù))的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10java int轉(zhuǎn)byte和long轉(zhuǎn)byte的方法
下面小編就為大家?guī)硪黄猨ava int轉(zhuǎn)byte和long轉(zhuǎn)byte的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10Spring Security LDAP實(shí)現(xiàn)身份驗(yàn)證的項(xiàng)目實(shí)踐
在本文中,我們涵蓋了“使用 Spring Boot 的 Spring Security LDAP 身份驗(yàn)證示例”的所有理論和示例部分,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08java根據(jù)擴(kuò)展名獲取系統(tǒng)圖標(biāo)和文件圖標(biāo)示例
這篇文章主要介紹了java根據(jù)擴(kuò)展名獲取系統(tǒng)圖標(biāo)和文件圖標(biāo)示例,需要的朋友可以參考下2014-03-03深入理解Mybatis中的resultType和resultMap
這篇文章給大家介紹了mybatis中的resultType和resultMap的用法實(shí)例講解,MyBatis中在查詢進(jìn)行select映射的時候,返回類型可以用resultType,也可以用resultMap,至于兩種用法區(qū)別,通過本文一起學(xué)習(xí)吧2016-09-09