SchedulerLock分布式定时任务锁

1.pom中引入依赖,这里使用redis作为锁

        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-spring</artifactId>
            <version>4.12.0</version>
        </dependency>
        <dependency>
            <groupId>net.javacrumbs.shedlock</groupId>
            <artifactId>shedlock-provider-redis-spring</artifactId>
            <version>4.12.0</version>
        </dependency>

2.yml配置redis连接

spring:
 redis:
    host: localhost
    port: 6379
    database: 0
    taskrelease: taskrelease

3.配置redis序列化

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        // 设置value的序列化规则和 key的序列化规则
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

4.线程池和分布式锁配置 


import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.redis.spring.RedisLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@EnableSchedulerLock(defaultLockAtMostFor = "PT30M")
@Slf4j
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

    @Resource
    ExecutorService scheduledThreadPoolExecutor;

    /**
     *
     */
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //最大线程数
        executor.setMaxPoolSize(8);
        //核心线程数
        executor.setCorePoolSize(8);
        //任务队列的大小
        executor.setQueueCapacity(100);
        //线程前缀名
        executor.setThreadNamePrefix("common-");
        //线程存活时间
        executor.setKeepAliveSeconds(30);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //线程初始化
        executor.initialize();
        return executor;
    }

    /**
     * 动态调度任务线程池
     */
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        // 线程池大学
        threadPoolTaskScheduler.setPoolSize(15);
        // 线程名称
        threadPoolTaskScheduler.setThreadNamePrefix("taskScheduler-");
        // 等待时长
        threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
        // 调度器shutdown被调用时等待当前被调度的任务完成
        threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
        return threadPoolTaskScheduler;
    }

    /**
     * Schedule定时任务指定线程池
     * Spring注解
     */
    @Bean(name = "scheduledThreadPoolExecutor")
    public ScheduledThreadPoolExecutor scheduledThreadPoolExecutor() {
        return new ScheduledThreadPoolExecutor(15);
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //显式为Scheduler指定线程池
        taskRegistrar.setScheduler(scheduledThreadPoolExecutor);
    }

    /**
     * 分布式锁
     * Schedule定时任务, Spring注解
     */
    @Bean
    public LockProvider lockProvider(RedisConnectionFactory connectionFactory) {
        return new RedisLockProvider(connectionFactory, System.getProperty("spring.profiles.active"));
    }
}

5.执行任务方法

    @Scheduled(cron = "0 0 23 * * ?")
    @SchedulerLock(name = "synchronizeAddDept", lockAtLeastFor = "PT15S")
    public void synchronizeAddDept() {
        StopWatch watch = new StopWatch();
        watch.start();
        log.info("====================> 同步部门数据开始, {}", LocalDateTime.now());
        watch.stop();
        log.info("====================> 同步部门数据结束, {}, 用时 {}", LocalDateTime.now(), 
        watch.getTotalTimeSeconds());
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Spring MVC中,实现分布式定时任务可以采用多种方式。其中一种常见的方式是使用分布式来保证在分布式环境下只有一个节点能够执行定时任务。 下面是一个简单的示例,演示如何使用Redis作为分布式来实现分布式定时任务: 1. 首先,确保你的项目中已经引入了Redis的依赖。 2. 创建一个分布式的工具类,例如 `DistributedLockUtil`。这个工具类可以包含如下方法: ```java import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.RedisScript; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Collections; import java.util.UUID; import java.util.concurrent.TimeUnit; @Component public class DistributedLockUtil { @Resource private RedisTemplate<String, Object> redisTemplate; /** * 获取分布式 * * @param lockKey 的key * @param requestId 请求标识,可以使用UUID等唯一标识符 * @param expireTime 的过期时间,单位:秒 * @return 是否获取到 */ public boolean tryLock(String lockKey, String requestId, long expireTime) { RedisScript<String> redisScript = new DefaultRedisScript<>( "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end", String.class); Object result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId, expireTime); return "OK".equals(result); } /** * 释放分布式 * * @param lockKey 的key * @param requestId 请求标识 */ public void releaseLock(String lockKey, String requestId) { RedisScript<Long> redisScript = new DefaultRedisScript<>( "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class); redisTemplate.execute(redisScript, Collections.singletonList(lockKey), requestId); } } ``` 3. 在需要加定时任务方法中,使用 `DistributedLockUtil` 来获取和释放分布式。例如: ```java @Component public class MyTask { @Resource private DistributedLockUtil distributedLockUtil; @Scheduled(cron = "0 0/5 * * * ?") // 每5分钟执行一次 public void myScheduledTask() { String lockKey = "my_task_lock"; String requestId = UUID.randomUUID().toString(); long expireTime = 300; // 的过期时间为300秒,即5分钟 // 尝试获取分布式 boolean locked = distributedLockUtil.tryLock(lockKey, requestId, expireTime); if (locked) { try { // 执行定时任务的业务逻辑 // ... } finally { // 释放分布式 distributedLockUtil.releaseLock(lockKey, requestId); } } } } ``` 在上述示例中,`MyTask` 类是一个定时任务类,使用了Spring的定时任务注解 `@Scheduled` 来指定定时任务的执行时间。在定时任务方法 `myScheduledTask()` 中,首先获取一个唯一的请求标识 `requestId`,然后使用 `DistributedLockUtil` 来尝试获取。如果成功获取到,则执行定时任务的业务逻辑;最后,在 `finally` 块中释放。 这样,通过使用Redis分布式,我们可以在分布式环境下实现定时任务的互斥执行,保证只有一个节点能够执行该定时任务。当然,你也可以选择其他分布式的实现方式,如基于数据库、ZooKeeper等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今朝花落悲颜色

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值