redis分布式锁

本文详细介绍了如何使用Redisson实现分布式锁,包括Redisson的安装、Lock锁、ReadWriteLock读写锁、闭锁CountDownLatch和信号量Semaphore的使用。强调了加锁时的原子操作、锁自动续期及解锁的正确处理,以及Redisson提供的各种锁的优势。
摘要由CSDN通过智能技术生成

分布式锁

原理与使用

我们可以在redis命令行通过setnx命令来完成分布式锁,加上NX后只有当key不存在时才会set

127.0.0.1:6379> set a a
OK
127.0.0.1:6379> set a b NX
(nil)

将分布式锁的简单逻辑转换为java业务代码如下

public void testLock(){
   
    // java代码中使用setIfAbsent()方法代理redis命令行中的setNX
    Boolean lock = redisTemplate.opsForValue.setIfAbsent("lock","111");
    if(lock){
   
        // 加锁成功 执行业务方法
        function();
        // 执行完成后,释放锁
        redisTemplate.delete("lock");
    } else {
   
        // 加锁失败,每隔一段时间后重试
        Thread.sleep(500);
        // 使用自旋的方式 重试
        testLock()
    }
}

问题:没有删除锁逻辑

可能在执行业务方法时出现了异常,或者是执行过程中宕机了,没有删除锁,这就会造成死锁

解决方法是:设置锁的自动过期时间,如果没有删除就自动删除。

public void testLock(){
   
    Boolean lock = redisTemplate.opsForValue.setIfAbsent("lock","111");
    if(lock){
   
        // 设置自动过期时间 30秒
        redisTemplate.expire("lock", 30, TimeUnit.SECONDS)
        function("业务方法");
        redisTemplate.delete("lock");
    } else {
   
        Thread.sleep(500);
        testLock()
    }
}

问题:现在往redis中存值和设置过期时间不是原子操作,有可能在if判断执行完后服务器断电或者宕机,那就还是会造成锁一直存在。

解决方法是:存值和设置过期时间变为原子操作,要么都成功,要么都不成功。

# redis命令行中 set命令的格式如下,其中可以加EX和PX都是设置过期时间,EX单位是秒   PX单位是毫秒
set key value [expiration EX seconds|PX milliseconds] [NX|XX]

# 如下所示
127.0.0.1:6379> set a aa EX 30 NX

现在java代码中的写法如下,在setIfAbsent()方法中还传入过期时间与过期单位

public void testLock(){
   
    // 设置自动过期时间 30秒
    Boolean lock = redisTemplate.opsForValue.setIfAbsent("lock","111", 30, TimeUnit.SECONDS);
    if(lock){
   
        function("业务方法");
        redisTemplate.delete("lock");
    } else {
   
        Thread.sleep(500);
        testLock()
    }
}

问题:可能业务方法执行耗时较长,锁自己过期了,我们直接删除,可能把别人正在持有的锁删除了

解决方法是:value之前是随便写的一个值,现在不随便写了,先生成一个uuid作为锁的值存入redis,删除锁之前先查询判断redis中存储的uuid和自己生成的uuid相同后才去删除锁。

public void testLock(){
   
    // 生成uuid
    String uuid = UUID.randomUUID().toString();
    
    Boolean lock = redisTemplate.opsForValue.setIfAbsent("lock",uuid, 30, TimeUnit.SECONDS);
    if(lock){
   
        function("业务方法");
        
        // 先判断uuid是否相同 再删除
        String uuidRedis = redisTemplate.opsForValue.get("lock");
        if(uuid
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值