用redis给定时任务Scheduled加分布式锁

9 篇文章 0 订阅

主要用到redis的setIfAbsent设置key,它的特点是:如果key已经存在,则返回false,可表示未获取到锁,否则返回true,表示获取到锁;

另外,定时任务的锁比一般提交事务的锁简单一些,如果同一个定时任务的多个实例抢一把锁,抢不到锁的可以退出,等待下一个时间周期,自动实现了锁自旋的效果;

还有,在定时任务的业务循环内部加一个延长锁时间的设置。

Talk is cheap. Show me the code:

@Component
@Slf4j
public class JobService {
    @Autowired
    private XxxService xxxService;
    @Autowired
    private RedisUtil redisUtil;
    //每分钟执行一次的任务
    @Scheduled(cron = "0 */1 * * * ?")
    public void xxxJob() {
        String key = "job:xxxDelayedDelete";
        Integer timeout = 180;
        //此处需要引入redission锁
        boolean lock = redisUtil.setIfAbsent(key, 1, timeout);
        if (!lock) return;
        Date now;
        Integer total = 0;
        try {
            log.info("===========开始任务xxxDelayedDeleteJob===========");
            Integer size = 0;
            do {
                size = 0;              
                final List<Xxx> xxxnList = xxxService.list();
                if (xxxList != null && xxxList.size() > 0) {
                    size = xxxList.size();
                    total += size;
                    Integer ret;
                    for (Xxx xxx: xxxList) {
                        //延长分布式锁时间,防止过期
                        redisUtil.set(key, 1, timeout);
                        //业务代码……
                        ret = xxxService.delete(xxx.getId());
                    }
                }
            } while (size > 0);
        } catch (Exception ex){
            log.error("------xxxDelayedDeleteJob "+ex.getMessage()+"," + JSONUtil.toJsonStr(ex.getStackTrace())+"--------");
        }finally {
            //释放锁
            redisUtil.del(key);
        }
        log.info("===========结束任务xxxDelayedDeleteJob====处理数量:"+total+"=======");
    }
}

在Spring Cloud中实现分布式锁可以使用ZooKeeper或Redis实现。这里以Redis为例,实现分布式锁的大致步骤如下: 1. 引入Redis依赖,配置Redis连接信息: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` ``` spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 2. 实现分布式锁类(以Redis为例): ``` @Component public class RedisLock { private RedisTemplate<String, Object> redisTemplate; private static final String LOCK_PREFIX = "lock:"; private static final long LOCK_EXPIRE = 30000L; // 锁的过期时间,单位毫秒 @Autowired public RedisLock(RedisTemplate<String, Object> redisTemplate) { this.redisTemplate = redisTemplate; } public boolean lock(String lockKey) { String key = LOCK_PREFIX + lockKey; String value = UUID.randomUUID().toString(); Boolean success = redisTemplate.opsForValue().setIfAbsent(key, value, LOCK_EXPIRE, TimeUnit.MILLISECONDS); return success != null && success; } public void unlock(String lockKey) { String key = LOCK_PREFIX + lockKey; redisTemplate.delete(key); } } ``` 3. 在定时任务中使用分布式锁: ``` @Component public class MyTask { private RedisLock redisLock; @Autowired public MyTask(RedisLock redisLock) { this.redisLock = redisLock; } @Scheduled(cron = "0/5 * * * * ?") public void run() { if (redisLock.lock("myTask")) { try { // 执行定时任务的逻辑 } finally { redisLock.unlock("myTask"); } } } } ``` 4. 在多个节点上部署相同的定时任务,并启动应用程序。每个节点都会尝试获取分布式锁,只有一个节点能够获取到锁并执行定时任务,其他节点会被阻塞。 需要注意的是,分布式锁的实现还需要考虑一些细节问题,如锁的粒度、重试机制、锁超时处理等等。这里的实现只是提供了一个基本的思路,具体实现中还需要根据业务需求进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值