redis 定时任务锁 分布式锁

基于 redisTemplate

在分布式集群环境中的最佳实践,其实无论是单机还是集群,保证原子性都是第一位的,如果能同时保证性能和高可用,那么就是一个可靠的分布式锁解决方案。

主要思路是:设置锁时,使用 redisTemplate,因为其底层实际包含了 setnx 、expire 的功能,起到了原子操作的效果.  给 key 设置随机且唯一的值,并且只有在 key 不存在时才设置成功返回 True,并且设置 key 的过期时间(最好是毫秒级别)

完整代码:

定义一个接口 和实现类:

public interface ILock {

    /**
     * 获取锁
     * @param timeout 超时自动解锁
     * @return 获取到锁返回true 获取失败则返回false
     */
    boolean tryLock(long timeout);

    /**
     * 释放锁
     */
    void unlock();
}
public class RedisLock implements ILock {

    private String name;

    private StringRedisTemplate stringRedisTemplate;

    public RedisLock (String name,StringRedisTemplate redisTemplate){
        this.name = name;
        this.stringRedisTemplate = redisTemplate;
    }

    private static final String KEY_PREFIX = "lock:";
    private static final String ID_PREFIX = UUID.randomUUID().toString();

    @Override
    public boolean tryLock(long timeoutSec) {
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX+name,threadId);
        Boolean successExpire = stringRedisTemplate.expire(KEY_PREFIX+name,timeoutSec, TimeUnit.SECONDS);
        return success && successExpire;
    }

    @Override
    public void unlock() {
        //获取线程标识
        String threadId = ID_PREFIX + Thread.currentThread().getId();
        //获取锁里面的标识
        String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX+name);
        if(threadId.equals(id)){
            stringRedisTemplate.delete(KEY_PREFIX+name);
        }
    }

使用:

@Component
@Slf4j
public class TestStatisticTask {
    

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Scheduled(cron = "${test.statistic.overview.cron:0 0/5 * * * ?}")
    public void run(){

        log.info("定时器统计信息启动...");
        RedisLock redisLock = new RedisLock("TestStatisticTask",stringRedisTemplate);
        if(!redisLock.tryLock(5*60)){
            log.info("定时器统计信息启动 未获取到锁");
            return;
        }
        try{
            //业务处理逻辑
        }catch (Exception ex){
            log.info("######定时器统计信息启动 异常:{}", ex.getMessage());
            log.error(ex.getMessage(), ex);
        }finally {
            redisLock.unlock();
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在实现给定时任务加上redis分布式锁的过程中,可以使用以下步骤: 1. 创建Redis连接池:首先需要创建Redis连接池,以便在后续的代码中可以方便地使用Redis操作。 2. 获取:在执行任务之前,需要获取以确保只有一个进程可以执行该任务。可以使用Redis的setnx命令来实现。如果setnx返回1,则表示获取成功,可以执行任务;如果返回0,则表示已经被其他进程持有,需要等待。 3. 执行任务:获取之后,就可以执行任务了。 4. 释放:任务执行完成之后,需要释放以便其他进程可以获取并执行任务。可以使用Redis的del命令删除。 下面是一个示例代码实现: ```python import redis import time class Task: def __init__(self): self.redis_pool = redis.ConnectionPool(host='localhost', port=6379, db=0) def run(self): if self.acquire_lock(): try: # 执行任务 print('start task...') time.sleep(5) print('task done.') finally: self.release_lock() def acquire_lock(self): redis_conn = redis.Redis(connection_pool=self.redis_pool) return redis_conn.setnx('task_lock', '1') def release_lock(self): redis_conn = redis.Redis(connection_pool=self.redis_pool) redis_conn.delete('task_lock') if __name__ == '__main__': task = Task() task.run() ``` 需要注意的是,由于网络延迟等原因,获取和释放的操作可能会失败。因此,需要对获取和释放的操作进行重试,以确保任务可以正确地执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值