HotFrameLearning(简称 HFL) Redis_12_redis分布式锁的3种实现方式
-
一、大致介绍
```
1、昨天介绍完redis的数据结构后,有小伙伴让本人讲讲redis的分布式锁,因此才有了此篇的由来,只是把我的节奏提前了而已;
2、接下来我就通过几种方式介绍一下分布式锁的使用;
```
二、源码分享
2.1 获取redis锁且快速失败
```
1、图1中,我们首先区分的是单机模式还是集群模式;
2、通过简单的 set 操作,但是要注意一点,set 时需要设置 expiryTimeMills 超时时间,而且设置key与设置expiryTimeMills需要是在一条原子语句里面,如果不是的话则会引起不必要的死锁问题;
3、至于为什么会引起死锁,假设 set key 与 set expiryTimeMills 是两条代码语句,当 set key 成功后,程序立马宕机了,那么这个 key 就没有失效时间,相当于永久有效,那么下次再次竞争获取该 key 时就永远都是失败的,因此要特别注意key与expiryTimeMills需要在同一条原子语句里面被执行;
4、当时又有人说,尝试一次就失败了,岂不是太不让调用方省心了,调用方想尝试多次还得自己写个代码玩玩,因此就有了下面尝试多次获取锁的操作;
```
2.2 尝试数次获取锁,获取不到则返回失败
```
1、图2中,同样我们首先区分的是单机模式还是集群模式;
2、通过在 tryLockFailFast 外面再套一层 while 循环处理,让入参多传入尝试次数retryTimes、尝试间隔时间retryIntervalMills 两个字段,即可满足多次尝试获取锁的诉求,这样调用方就能省心了;
3、虽然加锁是完事了,但是解锁呢,是不是直接删掉就完事了呢?请接着看~
```
2.3 释放redis锁且快速失败
```
1、图3中,同样我们首先区分的是单机模式还是集群模式;
2、只是在解锁的时候,有点点不同,我们需要先看看我们解锁的key对应的内存值是不是我们当初加锁的那个入参值?
3、为什么要这么判断呢?原因就是假设A线程加锁了,但是A的任务还没有执行完,此时key超时过期了,然后B线程又成功抢到了该锁,但是当B前脚抢到锁后A后脚就执行完了任务准备释放锁,那么就会将B已经获取到的锁释放掉,这么一操作已不是把不该释放的释放了,最终都会导致相应业务功能执行出问题的;
4、因此才会在解锁的时候,看下锁对应的值是不是当初加锁的那个值,如果一致则删除,否则删除失败;
5、但是这么一连串的 get del 是两个命令语句,但是解锁的真实诉求需要保证原子性,因此我们就需要 redis 给我们提供的 lua 脚本原子性执行多个命令语句;
6、但是但是,说到这,又会有小伙伴会问,怕担心任务执行太久导致redis超时,有啥好的方式处理呢?接着看~
```
2.4 阻塞获取redisson锁
```
1、图4中,用的redisson框架版本号为 redisson-3.11.2.jar,具体maven坐标大家去中央仓库看吧;
2、大家会想,这个redisson和之前的 tryUnLockFailFast 的加锁有啥区别呢?不也是执行加锁么?
3、答案当然不一样,redisson 底层会有一个续命线程,每到过期时间的的1/3时就自动重新将过期时间置为入参的过期时间值,所以即使业务线程的任务执行很久,也不会因为锁自动过期一事而烦恼,岂不快哉;
```
2.5 redisson知识扩展
```
1、图5中,我们稍微多看一眼 redisson 框架,然后我们会发现底层提供了很多的锁操作;
2、然而稍微再认真的同学仔细看看,会发现我们 JUC 有的类,这里都差不多实现了一番,可见 redisson 为分布式做了很多封装,方便调用方尽情的使用;
```
欢迎关注+点赞,您的肯定是对我最大的支持!!!