VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • Java中实现分布式定时任务

定时器Scheduler在平时使用比较频繁,在springboot中,配置好@Scheduled和@EnableScheduling之后,定时器就能正常执行,实现定时任务的功能。

 

但是在这样的情况下:如果开发的服务需要水平部署实现负载均衡,那么定时任务就会同时在多个服务实例上运行,那么一方面,可能由于定时任务的逻辑处理需要访问公共资源从而造成并发问题;另一方面,就算没有并发问题,那么一个同样的任务多个服务实例同时执行,也会造成资源的浪费。因此需要一种机制来保证多个服务实例之间的定时任务正常、合理地执行。

本文以shedlock为例,来实现分布式定时任务的控制。
 

ShedLock可以保证多个同样的定时任务在多个服务实例之间最多只执行一次,是一个在分布式环境中保证定时任务合理执行的框架,我们可以叫它分布式定时任务锁。

ShedLock的实现原理是采用公共存储实现的锁机制,使得同一时间点只有第一个执行定时任务的服务实例能执行成功,并在公共存储中存储"我正在执行任务,从什么时候(预计)执行到什么时候",其他服务实例执行时如果发现任务正在执行,则直接跳过本次执行,从而保证同一时间一个任务只被执行一次。

ShedLock的公共存储目前支持的有:
Monogo
DynamoDB
JdbcTemplate
ZooKeeper (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 ) 
);
复制代码

 

第四步,添加具体任务类
复制代码
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为锁默认持有时间,会覆盖启动类中的默认持有时间
    @SchedulerLock(name = "demo", lockAtMostFor = "70m")
    public void print() throws InterruptedException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        log.warn("当前时间:"+df.format(new Date()));
    }
}
复制代码

 

接着,我们复制一份代码,分别启动两个实例来看结果
 
 
 
 
 
 
 
数据库记录
 
 
 
@SchedulerLock注解参数说明
name:定时任务的名字,就是数据库中的内个主键
lockAtMostFor:锁的最大时间单位为毫秒
lockAtLeastFor:锁的最小时间单位为毫秒
 
对了,还有启动类的配置
复制代码
@SpringBootApplication
@MapperScan("com.example.test.mapper")
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "10m")  // 默认的锁的时间
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


相关教程