Redis分布式锁

原创转载请注明出处:<https://www.cnblogs.com/agilestyle/p/11605323.html&gt;

大部分开发人员利用Redis 实现分布式锁的方式,都是使用SETNX+EXPIRE 组合来实现

![]()

这种方式实现的分布式锁,是通过setnx 方法设置锁,如果lockKey 存在,则返回失败,否则返回成功。设置成功之后,为了能在完成同步代码之后成功释放锁,方法中还需要使用expire 方法给lockKey 值设置一个过期时间,确认key值删除,避免出现锁无法释放,导致下一个线程无法获取到锁,即死锁问题。

如果程序在设置过期时间之前、设置锁之后出现崩溃,此时如果lockKey 没有设置过期时间,将会出现死锁问题,这种问题的根源在于setnx 和expire 是两条指令而不是原子指令。

在Redis2.8版本中,Redis的作者加入了set指令的扩展参数,使得setnx 和 expire 指令 可以一起执行。示例代码如下:

RedisDistributedLock.java

 1 package org.fool.spring.util;
 2 
 3 import redis.clients.jedis.Jedis;
 4 
 5 public class RedisDistributedLock {
 6 
 7     private static final String LOCK_DEFAULT_FLAG = &quot;true&quot;;
 8     private static final String LOCK_SUCCESS = &quot;OK&quot;;
 9     private static final String SET_IF_NOT_EXIST = &quot;NX&quot;;
10     private static final String SET_WITH_EXPIRE_TIME = &quot;PX&quot;;
11 
12     private Jedis jedis;
13     private String lockKey;
14 
15     RedisDistributedLock(Jedis jedis, String lockKey) {
16         this.jedis = jedis;
17         this.lockKey = lockKey;
18     }
19 
20     /**
21      * 尝试获取分布式锁
22      *
23      * @param expireTime 超期时间(ms)
24      * @return 是否获取成功
25      */
26     public boolean tryLock(int expireTime) {
27         String result = jedis.set(lockKey, LOCK_DEFAULT_FLAG, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
28 
29         return LOCK_SUCCESS.equals(result);
30     }
31 
32     public void unlock() throws Exception {
33         jedis.del(lockKey);
34     }
35 
36     public boolean isAcquiredInThisProcess() {
37         String result = jedis.get(lockKey);
38 
39         return LOCK_DEFAULT_FLAG.equals(result);
40     }
41 
42 }

![]()

Test

![]()

执行第一次Test

![]()

在60s秒执行第二次Test,由于第一次Test还在执行中(即锁还没有释放),导致没有获取到锁

![]()

Note:

Redis的分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行的时间太长,以至于超出了锁的超时限制,就会出现超时问题。

因为这时候第一个线程持有的锁过期了,临界区的逻辑还没有执行完,而同时第二个线程就提前重新持有了这把锁,导致临界区代码不能得到严格串行执行。

为了避免这个问题,Redis分布式锁不要用于较长时间的任务。

这个方案是目前最优的分布式锁方案,但如果是在Redis集群环境下,依然存在问题。由于Redis集群数据同步到各个节点时是异步的,如果在Master节点获取到锁后,在没有同步到其它节点时,Master节点崩溃了,此时新的Master节点依然可以获取锁,所以多个应用服务可以同时获取到锁。集群模式下推荐使用 Redisson

Reference

<https://time.geekbang.org/column/article/125983&gt;

<https://www.redis.net.cn/order/3552.html&gt;

声明:该文章系转载,转载该文章的目的在于更广泛的传递信息,并不代表本网站赞同其观点,文章内容仅供参考。

本站是一个个人学习和交流平台,网站上部分文章为网站管理员和网友从相关媒体转载而来,并不用于任何商业目的,内容为作者个人观点, 并不代表本网站赞同其观点和对其真实性负责。

我们已经尽可能的对作者和来源进行了通告,但是可能由于能力有限或疏忽,导致作者和来源有误,亦可能您并不期望您的作品在我们的网站上发布。我们为这些问题向您致歉,如果您在我站上发现此类问题,请及时联系我们,我们将根据您的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。