Redis的Setnx命令实现分布式锁

Redis的Setnx命令实现分布式锁
最新回答
花若怜

2022-06-19 08:30:51

首先,分布式锁和我们平常讲到的锁原理基本一样,目的就是确保在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法、变量。

在一个进程中,也就是一个jvm或者说应用中,我们很容易去处理控制,在 java.util 并发包中已经为我们提供了这些方法去加锁,比如 synchronized 关键字或者 Lock 锁,都可以处理。

但是如果在分布式环境下,要保证多个线程同时只有1个能访问某个资源,就需要用到分布式锁。这里我们将介绍用Redis的 setnx 命令来实现分布式锁。

其实目前通常所说的 setnx 命令,并非单指redis的 setnx key value 这条命令,这条命令可能会在后期redis版本中删除。

一般代指redis中对 set 命令加上 nx 参数进行使用, set 这个命令,目前已经支持这么多参数可选:

从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:

注入bean

这里同时启动5个线程并发往redis中存储 lock 这个key(key可以自定义,但需要一致),同时设置10秒的过期时间。
setIfAbsent 这个函数实现的功能与 setnx 命令一样,代表如果没有这个key则set成功获取到锁,否则set失败没有获取到锁。
获得锁后进行资源的操作,最后释放锁。

执行效果

可以看到同时只有1个线程能够获取到锁。

使用 setnx 命令方式虽然操作比较简单方便,但是会有如下问题:

可以在再次获取锁时,如果锁被占用就get值,判断值是否是当前线程存的随机值,如果是则再次执行 set 命令重新上锁;当然为了保证

原子性
这些操作都要用 lua 脚本来执行。

可以使用 while 循环重复执行 setnx 命令,并设置一个超时时间退出循环。

可以尽量把锁自动过期的时间设的冗余一些。但也不能彻底解决。

可以在删除锁的时候先get值,判断值是否是当前线程存的随机值,只有相同才执行删锁的操作;当然也要使用 lua 脚本执行来保证原子性。

分布式锁需要满足的特性

综上:使用 setnx 命令来实现分布式锁并不是一个很严谨的方案,如果是Java

技术栈
,我们可以使用 Redisson 库来解决以上问题,接下来的文章会介绍如何使用。

Redisson实现分布式锁
Redlock实现分布式锁