Redisson分布式锁

我们先配置下RedissonClient并注册为Bean,指定锁的名称,通过 getLock,拿到redissonLock。

因为我们上面没有传参数,调用这个无参的方法,其他方法分别是未设置等待时间(没有设置重试功能,waitTime默认为-1),未设置锁的过期时间(开启看门狗机制,leaseTime默认为-1)

注意这些方法返回值都是RFuture<Boolean>

重试机制:

对于可重试功能,表明在调用tryLock方法时,给了第一个参数waitTime,即上面的第三,四个方法。这两个方法区别就是有无看门狗机制,下面会讲。 我们先进入第四个方法的调用。

会调用tryAcquireAsync的方法,通过它的回调结果去进行相应的操作。

先判断是否设置了锁的过期时间,即判断是否开启了看门狗机制,这里我们进入第一个if分支(未开启看门狗机制)

这个方法先进行统一判定,如果有看门狗机制则读取锁的过期时间,没有则直接转换成毫秒,然后进行一段lua脚本。逻辑就是锁的重入机制嘛,当前是否进来过,没进来的话,则通过hincrby方法创建hash结构,同时设置字段为1,并刷新过期时间。进来过的话,则直接给当前线程id的次数+1,同时刷新过期时间。注意,这里成功都是返回nil,失败返回key的过期时间。后面会根据lua脚本的返回值去做进一步判断。

回到这张图,上面三张图,我们根据lua脚本的返回值,如果ttl==null,说明执行成功了,返回true,如果执行失败(可能是没有拿到锁嘛),就会计算锁的等待时间,是否还需要继续等待,如果超过了等待时间waitTime,则直接返回false,否则开启订阅subscribe(目标线程id)

如果订阅的那个线程释放了锁,它就会publish给所有订阅了的线程一个信号(后面会讲),那我们就会重新去竞争这把锁,进入onComplete回调方法,ex是异常信息,AtomicReference是一个超时任务(定时任务,即指定时间内没有完成,则会触发的一个任务)

这个超时任务的创建是在!subscribeFuture.isDone()这个if分支触发的,即如果订阅失败,则它会去创建这个定时任务,并存放在futureRef变量中。而futureRef.get()!=null if分支是为了判断当前是否有定时任务,如果能进入这里,前提一定是完成了订阅,同时没有报错的前提下,这个时候再把定时任务给取消掉。当然,订阅成功不代表一定能抢到锁,会先进入tryLockAsync方法

通过subscribeFuture获取到entry,当锁发生变化时,latch 会被释放,从而允许线程继续执行。

如果 latch 可以获取,说明锁的状态发生了变化,可以继续尝试获取锁。当然,如果没拿到信号量,就开启监听器,以及一个定时任务,逻辑和上面那个定时任务差不多,都是去等别人发消息。

当信号量释放的时候,就会触发这个监听器,然后尝试去获得锁。

避免超时释放:

上面也有讲,在tryLock的时候,不设置锁的leaseTime(过期时间)scheduleExpirationRenewal

同时这里还有个很重要的map

可重入:上面有讲,其实就是在获取锁的时候,多了一个判定, 是否是当前线程id拿到的锁,是的话,hash数据结构中的value字段次数+1,同样的,如果释放锁,会先去给value -1,然后也会通过当前线程id去判断次数此时是否>0,如果count>0,说明还不能删除这个key嘛,如果count = 0 ,则del这个key。

相关推荐
Data跳动4 小时前
Spark内存都消耗在哪里了?
大数据·分布式·spark
Java程序之猿5 小时前
微服务分布式(一、项目初始化)
分布式·微服务·架构
来一杯龙舌兰6 小时前
【RabbitMQ】RabbitMQ保证消息不丢失的N种策略的思想总结
分布式·rabbitmq·ruby·持久化·ack·消息确认
节点。csn7 小时前
Hadoop yarn安装
大数据·hadoop·分布式
NiNg_1_2349 小时前
基于Hadoop的数据清洗
大数据·hadoop·分布式
隔着天花板看星星10 小时前
Spark-Streaming集成Kafka
大数据·分布式·中间件·spark·kafka
技术路上的苦行僧14 小时前
分布式专题(8)之MongoDB存储原理&多文档事务详解
数据库·分布式·mongodb
龙哥·三年风水14 小时前
workman服务端开发模式-应用开发-后端api推送修改二
分布式·gateway·php
小小工匠15 小时前
分布式协同 - 分布式事务_2PC & 3PC解决方案
分布式·分布式事务·2pc·3pc
闯闯的日常分享17 小时前
分布式锁的原理分析
分布式