用于在Java Spring框架中定時執行特定任務的注解 @Scheduled,它能夠指定方法在特定時間間隔或特定時間點執行。默認參數是cron,cron參數被用來定義一個Cron表達式,它代表了任務執行的時間規則
參數如下
Cron
這是是一種時間表達式,用于表示定時任務的執行規則。在Spring中,@Scheduled注解的cron參數就是用來設置Cron表達式的。Cron表達式的基本格式為:
secdond minute hour dayOfMonth month dayOfWeek year
每個字段的含義如下:
- second:秒(0-59)
- minute:分鐘(0-59)
- hour:小時(0-23)
- dayOfMonth:月份中的某一天(1-31)
- month:月份(1-12或者 JAN-DEC)
- dayOfWeek:星期中的某一天(1-7或者 SUN-SAT)
- year:年份(留空表示任何年份)
使用*表示匹配任意值,例如,在month字段中表示每個月,而在dayOfWeek字段中表示每一天。除了之外,你還可以使用一些其他符號,比如:
8.-:表示一個范圍,比如 1-5 表示1到5。
9.,:表示一個列表,比如 1,3,5 表示1、3和5。
10./:表示間隔,比如 0/15 表示每隔15分鐘。
例如,要設置每天上午10點執行任務,Cron表達式可以是 0 0 10 * * ?。 0 0/1 * * * ?,表示每隔一分鐘執行一次任務。
示例:
@Scheduled(cron = “0 15 10 * * ?”) // 每天上午10:15執行
fixedRate
這個參數定義了方法調用之間的固定周期,單位為毫秒。不論前一次方法執行花費了多長時間,都會按照這個間隔執行。如果上一個任務堵塞不排除臟數據的風險
示例:
@Scheduled(fixedRate = 1000) // 每1000毫秒執行一次
fixedDelay
這個參數定義了在上一次方法執行完畢后到下一次開始執行的間隔時間,單位也是毫秒。不同于 fixedRate,fixedDelay 會等待前一次方法執行完成后才開始計時。
示例:
@Scheduled(fixedDelay = 1000) // 完成后1000毫秒再次執行
initialDelay
:這個參數用來定義延遲首次執行任務的時間,單位為毫秒。它通常與 fixedRate 或 fixedDelay 結合使用,用來設置啟動后延遲執行任務。
示例:
@Scheduled(fixedRate = 1000, initialDelay = 1000) // 啟動后延遲1000毫秒,之后每1000毫秒執行一次
zone
:用于指定 cron 表達式的時區,默認是服務器的本地時區。
示例:
@Scheduled(cron = "0 15 10 * * ?", zone = "America/New_York") // 指定時區為紐約
使用 @Scheduled 注解需要在 Spring 配置中啟用定時任務(通過注解 @EnableScheduling)。這樣,Spring 的任務調度器就會自動識別使用了 @Scheduled 注解的方法,并根據設定的規則執行這些方法。
最后在啟動類上開啟該方法@EnableScheduling
多個服務導致資源沖突問題
當多個服務同時操作一個任務就會造成數據沖突,所以就需要分布式鎖,redis的setnx,無狀態,可共享,讀取塊就能成為很好的解決方案
redisssesion實現分布式鎖
也可以只有使用redis 上鎖方法
public String tryLock(String name, long expire) {name = name + "_lock";String token = UUID.randomUUID().toString();RedisConnectionFactory factory = stringRedisTemplate.getConnectionFactory();RedisConnection conn = factory.getConnection();try {//參考redis命令:在redis中存入數據 數據明 uuid token 為鎖的名字
// 因為這個數據的名字都是name+_locak 所以每次調用加鎖方法setnx 只有一個成功調用的才能才能成功的保存的一個鎖數據,其他的只能無法設置//set key value [EX seconds] [PX milliseconds] [NX|XX]Boolean result = conn.set(name.getBytes(),token.getBytes(),Expiration.from(expire, TimeUnit.MILLISECONDS),RedisStringCommands.SetOption.SET_IF_ABSENT //NX);if (result != null && result)return token;} finally {RedisConnectionUtils.releaseConnection(conn, factory,false);}return null;}
方法調用
因為我的定時任務是每隔1minute 執行一次,所以每次上鎖30s,讓其他任務線程無法獲取,這里是統一名字實際業務開發,一個數據的操作可以使用一個數據的主鍵+前后綴來作為鎖名
@Scheduled(cron = "0 */1 * * * ?")public void refresh(){String token = cacheService.tryLock("FUTURE_TASK_SYNC", 1000 * 30);if(StringUtils.isNotBlank(token)){//。。。。。執行邏輯}}}