分布式锁4-Redisson分布式锁实现与看门狗原理

本文介绍了Redisson在Redis基础上提供的分布式锁解决方案,包括其基本使用方法、配置方式及分布式锁的实现原理。通过实例展示了如何在Java应用中轻松集成Redisson实现高性能分布式锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.Redisson介绍

   Redisson 是架设在 Redis 基础上的一个 Java 驻内存数据网格(In-Memory Data Grid)。充分的利用了 Redis 键值数据库提供的一系列优势, 基于 Java 实用工具包中常用接口,为使用者提供了一系列具有分布式特性的常用工具类。 使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度。同时结合各富特色的分布式服务,更进一步简化了分布式环境中程序相互之间的协作。

   以上是官网的介绍,主要就是基于redis分布式锁实现了jvm ReentrantLock锁的几乎所有功能, 读写锁,重入锁,公平锁,信号量等等.让你就像调用本地锁一样简单.可以说非常强大.

官方文档:Redisson

二.分布式锁的运用

1.引入依赖.

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.12.0</version>
        </dependency>

2.增加配置类.

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient(){
        Config config = new Config();
        //集群配置
//        config.useClusterServers()
//                .setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒
//                //可以用"rediss://"来启用SSL连接
//                .addNodeAddress("redis://127.0.0.1:7000", "redis://127.0.0.1:7001")
//                .addNodeAddress("redis://127.0.0.1:7002");
        //单节点配置
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

3.简单代码实现

注意:此分布式锁默认实现均为可重入锁,和jvm锁一样,持有当前锁的线程可以重复获取锁

1.不指定加锁时间,会默认启动看门狗.自动帮你的锁进行续期.
    @Autowired
    RedissonClient redissonClient;

     public void test(){
        //传入的名称要注意,名称一样即为同一把锁
        RLock lock = redissonClient.getLock("lock");
        lock.lock();
        try{
            //执行具体的业务逻辑
            

        }finally {
            lock.unlock();
        }

    }
2.指定加锁时间,不启用看门狗续期,到期自动解锁.
    @Autowired
    RedissonClient redissonClient;

     public void test(){
        //传入的名称要注意,名称一样即为同一把锁
        RLock lock = redissonClient.getLock("lock");
        lock.lock(30,TimeUnit.SECONDS);
        //执行具体的业务逻辑
        
    }

注意传入的名称为同一个,即为同一把锁,所以这个锁的名称就涉及到锁的粒度,锁的粒度是越小越好的

此外,Reddssion还提供了公平锁,红锁,读写锁,信号量等等,这里不再说明,可以参照文档.
官方文档:Redisson

三.分布式锁实现原理

这里以不指定过期时间,使用看门狗进行续期的情况进行分析.

加锁过程

这里会默认传一个-1的过期时间,以便后续进行判断,是-1的话则使用看门狗续期

在这里插入图片描述
然后进行尝试加锁

在这里插入图片描述

这里采用了异步加锁的方式,当加锁成功后,回调执行看门狗逻辑的方法.

在这里插入图片描述
这里我们先看它的异步加锁方法:
其实最主要的就是执行了一段lua脚本,保证了多个操作的原子性
根据这个lua脚本,也能看出这个锁是可重入的,如果当前key存在的话,就将value进行+1.

在这里插入图片描述

看门狗续期过程

这里我们再回到使用看门狗进行续期的方法

在这里插入图片描述
在整个加锁过程中,这个看门狗的实现还是很细节的,这是一个比较复杂的操作.

因为这里有一个问题,我们知道,如果想对一个key进行续期,我们最简单的可以指定一个定时任务,重复的去执行这个续期逻辑.但是在一个项目中,可能会有很多不同的分布式锁, 那每一个锁都单独的一个定时任务吗?那很多锁的情况下岂不是要很多的定时任务?这样的话对项目影响岂不是很大?

那Reddssion是怎样处理的呢?我们一起看一下
在这里插入图片描述
这里往一个东西里面添加了定时任务,这个定时任务具体要做的就是使用lua脚本对key进行续期,续期成功后,递归执行这个方法,为什么要递归呢?这个定时任务谁控制去执行的呢?

在这里插入图片描述
我们点开 commandExecutor.getConnectionManager().newTimeout()方法,看看它做了什么?

在这里插入图片描述
   看到这里,可能有的人就知道了,这里其实运用了HashedWheelTimer类,它是netty内部的一个工具类,主要运用了时间轮算法,内部有且仅有一个worker线程,可以动态的添加延时任务,但是每个任务只会执行一次,所以上面会递归的去添加任务.

   而因为其内部只有一个worker线程,所以并不会对项目影响很大,有小伙伴不了解这个HashedWheelTimer,可以看下这个文章时间轮算法HashedWheelTimer
看完就会理解看门狗为什么要这样实现了.

这里要注意:
如果你不主动释放锁的话,redisson中的看门狗默认会一直帮你续期,即使程序出现异常或者线程中断,除非整个项目停止,这个时候看门狗也停止了,也就不会再续期了.所以一定要记得释放锁.

今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

### Redisson 分布式锁中超时看门狗实现原理分布式环境中,为了防止死锁并确保资源能够及时释放,通常会对锁设置一个超时时间。然而,在实际应用中,可能会遇到业务逻辑处理时间超过预期的情况。为此,Redisson引入了看门狗(watchdog)机制来解决这一问题。 当客户端成功获取到锁之后,Redisson内部会启动一个定时器任务,该任务负责定期检查当前持有的锁是否已经接近过期[^2]。具体而言: - **默认配置**:每次获得锁时,Redisson会给这个锁设定一个初始的有效期限,默认情况下为30秒。 - **续期操作**:一旦持有锁的时间超过了总有效期的一半以上(例如15秒),看门狗就会触发一次续期请求,将锁的有效期再延长至完整的30秒。这样的过程会持续进行,只要锁还没有被显式地解锁或因其他原因失效。 - **间隔策略**:按照预设算法计算下次续期的最佳时机,通常是每经过大约三分之一的有效期间隔就尝试更新一次锁的有效期。比如,假设有效时间为30秒,则每隔约10秒钟左右就会有一次续期动作[^3]。 这种设计可以有效地避免因为网络延迟或其他不可预见的因素而导致提前失去锁控制权的风险,同时也保障了即使是在极端条件下也能安全可靠地管理共享资源访问权限。 此外,值得注意的是,只有当线程确实处于活动状态并且继续占用着对应的锁实例时,才会执行上述提到的自动延展流程;反之,如果线程正常结束或者异常终止,则不再会有任何关于此特定锁的操作发生[^4]。 ```java // Java代码示例展示如何使用RedissonClient创建RLock对象,并通过tryLock方法指定等待时间和租约时间 import org.redisson.api.RLock; import java.util.concurrent.TimeUnit; public class DistributedLockExample { private final RedissonClient redissonClient; // 假定已初始化 public void acquireDistributedLock() throws InterruptedException { RLock lock = redissonClient.getLock("myLock"); boolean isLocked = lock.tryLock(10, 30, TimeUnit.SECONDS); // 尝试加锁,最多等待10秒,锁定后保持30秒 if (isLocked) { try { // 执行临界区内的业务逻辑... } finally { lock.unlock(); // 确保最终总是能释放锁 } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员bling

义父,感谢支持

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

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

打赏作者

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

抵扣说明:

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

余额充值