【Redis】Redis分布式锁的实现核心思路

一、实现思路

实现分布式锁时需要实现的两个基本方法:

  • 获取锁:

    • 互斥:确保只能有一个线程获取锁,使用redis中的setnx操作
    • 非阻塞:尝试一次,成功返回true,失败返回false
    image-20240528100418138
  • 释放锁:

    • 手动释放
    • 超时释放:获取锁时添加一个超时时间
    image-20240528100431171

但是这里还存在一个问题:我们加过期时间的目的就是为了避免因为服务宕机导致锁无法释放。但是如果我执行 setnx 成功了,但还没来得及执行 expire 就已经宕机了,那是不是依然没有办法释放?所以我们必须保证setnx这个获取锁的动作、和添加锁过期时间,这两者要么同时成功,要么同时失败,因此需要具有原子性,那这业务该怎么做呢?

其实redis的set命令后面可以跟上很多参数,通过EX就可以指定过期时间,以秒为单位,PS是以毫秒为单位。

除此之外可以减,它后面还可以跟上NX,这个NX效果就跟setnx一样,只有当key不存在的时候,才能去set

image-20240528101140564

所以说我们可以在一个set命令中通过设置参数,同时实现nx和过期时间的效果,这样就可以实现原子性的操作

image-20240528101245490

并且我们给它也设置了有效期,过10s可以发现已经过期了

image-20240528101417513

因此最终的方案如下图

image-20240528101527369

二、思考

其实到这已经可以实现分布式锁了,但是还有一个小问题。

在获取锁的时候,要么成功,要么失败。成功了返回OK,失败返回 nil,但是失败了以后我们又该怎么做呢?

其实在我们JDK中提供的锁有两种机制,一种是:如果获取失败,就会阻塞等待,等到有人释放锁为止,也就是说是一种阻塞式的获取。

还有一种方式就是非阻塞式的获取,也就是说我来尝试获取锁,如果我获取失败了,我就会立即结束,返回一个结果,而不是一直尝试一直等待。

在这我们会实现非阻塞机制,因为阻塞式第一、对CPU是有一定浪费的,第二、这种阻塞式实现起来相对会比较麻烦一些。

因此我们会利用非阻塞的方式,也就是说我尝试一次,成功返回true,失败返回false,然后我就不再尝试了。


三、整体流程

我们利用redis 的setNx 方法,当有多个线程进入时,我们就利用该方法,第一个线程进入时,redis 中就有这个key 了,返回了nil;如果结果是OK,则表示他抢到了锁,那么他去执行业务,然后再删除锁,退出锁逻辑

image-20240528102630864
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值