集羣,如果沒有鎖,就會同時跑同一個定時,浪費資源不說,還容易出bug,如下所示
現在ShedLock可以解決這個問題
1導包
1)pom文件
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- shedlock -->
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-provider-jdbc-template</artifactId>
<version>2.5.0</version>
</dependency>
2)yaml 依賴mysql
spring:
datasource:
url: jdbc:mysql://localhost:3306/basedemo?useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
username: root
password: '123'
2.啓動類打開 @EnableSchedulerLock(defaultLockAtMostFor = "PT10S")
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT10S")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
配置類
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 javax.sql.DataSource;
@Configuration
public class ScheduledLockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
}
建表sql
CREATE TABLE shedlock(
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)
3.例子
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class SchedulTest {
public static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final int lockTime = 1000;
@Scheduled(cron = "0/10 * * * * ?")
@SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtMostFor = lockTime, lockAtLeastFor = lockTime)
public void reportCurrentTime() {
System.out.println("現在時間是" + format.format(new Date())+ Thread.currentThread().getName());
}
}
如下圖所示,每次只跑一個定時
4.下面詳細解釋以下配置
@SchedulerLock註釋有幾個用途。首先,只有帶註釋的方法被鎖定,庫會忽略所有其他計劃的任務。您還必須爲鎖指定名稱。同一時間只能執行一個具有相同名稱的任務。
您還可以設置lockAtMostFor屬性,該屬性指定在執行節點死亡時鎖應該保留多長時間。這只是一個回退,在正常情況下,鎖會在任務完成時釋放。您必須將lockAtMostFor設置爲一個比正常執行時間長得多的值。如果任務花費的時間超過lockAtMostFor,結果的行爲可能是不可預測的(更多的進程將有效地持有鎖)。
最後,您可以設置lockAtLeastFor屬性,該屬性指定鎖應該保存的最短時間。它的主要目的是防止多個節點執行非常短的任務和節點之間的時鐘差異。
通過設置lockAtMostFor,我們確保即使節點死亡,鎖也被釋放;通過設置lockAtLeastFor,我們確保它不會在15分鐘內執行超過一次。請注意,對於執行任務的節點死亡的情況,lockAtMostFor只是一個安全網,因此將它設置爲一個比最大估計執行時間大得多的時間。如果任務花費的時間比lockAtMostFor更長,則可能再次執行該任務,結果將是不可預測的(更多進程將持有鎖)。