Redis分布式锁实现Redisson 15问(四)

pivoteic
发布于 2022-6-17 16:57
浏览
0收藏

 

八、如何实现不同线程加锁的互斥

 

上面我们分析了第一次加锁逻辑和可重入加锁的逻辑,因为lua脚本加锁的逻辑同时只有一个线程能够执行(redis是单线程的原因),所以一旦有线程加锁成功,那么另一个线程来加锁,前面两个if条件都不成立,最后通过调用redis的pttl命令返回锁的剩余的过期时间回去。

 

这样,客户端就根据返回值来判断是否加锁成功,因为第一次加锁和可重入加锁的返回值都是nil,而加锁失败就返回了锁的剩余过期时间。

 

所以加锁的lua脚本通过条件判断就实现了加锁的互斥操作,保证其它线程无法加锁成功。

Redis分布式锁实现Redisson 15问(四)-鸿蒙开发者社区

所以总的来说,加锁的lua脚本实现了第一次加锁、可重入加锁和加锁互斥的逻辑。

 

九、加锁失败之后如何实现阻塞等待加锁

 

从上面分析,加锁失败之后,会走如下的代码。

Redis分布式锁实现Redisson 15问(四)-鸿蒙开发者社区

从这里可以看出,最终会执行死循环(自旋)地的方式来不停地通过tryAcquire方法来尝试加锁,直到加锁成功之后才会跳出死循环,如果一直没有成功加锁,那么就会一直旋转下去,所谓的阻塞,实际上就是自旋加锁的方式。

 

但是这种阻塞可能会产生问题,因为如果其它线程释放锁失败,那么这个阻塞加锁的线程会一直阻塞加锁,这肯定会出问题的。所以有没有能够可以指定阻塞的时间,如果超过一定时间还未加锁成功的话,那么就放弃加锁的方法。答案肯定是有的,接着往下看。

 

十、如何实现阻塞等待一定时间还未加锁成功就放弃加锁

 

超时放弃加锁的方法

 

boolean tryLock(long waitTime, long leaseTime, TimeUnit unit)
boolean tryLock(long time, TimeUnit unit)


通过waitTime参数或者time参数来指定超时时间。这两个方法的主要区别就是上面的方法支持指定锁超时时间,下面的方法不支持锁超时自动释放。

 

tryLock(long time, TimeUnit unit)这个方法最后也是调用tryLock(long waitTime, long leaseTime, TimeUnit unit)方法的实现。代码如下。

Redis分布式锁实现Redisson 15问(四)-鸿蒙开发者社区

其实通过源码就可以看出是怎么实现一定时间之内还未获取到锁就放弃加锁的逻辑,其实相比于一直获取锁,主要是加了超时的判断,如果超时了,那么就退出循环,放弃加锁,

 

十一、如何实现公平锁

 

1)什么是公平锁

 

所谓的公平锁就是指线程成功加锁的顺序跟线程来加锁的顺序是一样,实现了先来先成功加锁的特性,所以叫公平锁。就跟排队一样,不插队才叫公平。

 

前面几节讲的RedissonLock的实现是非公平锁,但是里面的一些机制,比如看门狗都是一样的。

 

2)公平锁和非公平锁的比较

 

公平锁的优点是按序平均分配锁资源,不会出现线程饿死的情况,它的缺点是按序唤醒线程的开销大,执行性能不高。非公平锁的优点是执行效率高,谁先获取到锁,锁就属于谁,不会“按资排辈”以及顺序唤醒,但缺点是资源分配随机性强,可能会出现线程饿死的情况。

 

3)如何使用公平锁?

 

通过RedissonClient的getFairLock就可以获取到公平锁。Redisson对于公平锁的实现是RedissonFairLock类,通过RedissonFairLock来加锁,就能实现公平锁的特性,使用代码如下。

Redis分布式锁实现Redisson 15问(四)-鸿蒙开发者社区

RedissonFairLock继承了RedissonLock,主要是重写了tryLockInnerAsync方法,也就是加锁逻辑的方法。

 

下面来分析一下RedissonFairLock的加锁逻辑。

Redis分布式锁实现Redisson 15问(四)-鸿蒙开发者社区

这段加锁的逻辑很长,我就简单说一下这段lua脚本干了啥。

 

当线程来加锁的时候,如果加锁失败了,那么会将线程扔到一个set集合中,这样就按照加锁的顺序给线程排队,set集合的头部的线程就代表了接下来能够加锁成功的线程。当有线程释放了锁之后,其它加锁失败的线程就会来继续加锁,加锁之前会先判断一下set集合的头部的线程跟当前要加锁的线程是不是同一个,如果是的话,那就加锁成功,如果不是的话,那么就加锁失败,这样就实现了加锁的顺序性。

 

当然这段lua脚本还做了一些其它细节的事,这里就不再赘述。

 

文章转自公众号:三友的java日记

标签
已于2022-6-17 16:57:57修改
收藏
回复
举报
回复
    相关推荐