加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程 > 正文

Redis实现漫衍式锁的正确姿势

发布时间:2019-01-26 11:38:29 所属栏目:编程 来源:编辑之路
导读:一、媒介 在我们一般事变中,除了Spring和Mybatis外,用到最多无外乎漫衍式缓存框架Redis。可是许多事变许多年的伴侣对Redis还处于一个最基本的行使和熟悉。以是我就像把本身对漫衍式缓存的一些领略和应用清算一个系列,但愿可以辅佐到各人加深对Redis的理
副问题[/!--empirenews.page--]

Redis实现漫衍式锁的正确姿势

一、媒介

在我们一般事变中,除了Spring和Mybatis外,用到最多无外乎漫衍式缓存框架——Redis。可是许多事变许多年的伴侣对Redis还处于一个最基本的行使和熟悉。以是我就像把本身对漫衍式缓存的一些领略和应用清算一个系列,但愿可以辅佐到各人加深对Redis的领略。本系列的文章思绪先从Redis的应用开始。再理会Redis的内部实现道理。最后以常常会问到Redist相干的口试题为末了。

二、漫衍式锁的实现要点

为了实现漫衍式锁,必要确保锁同时满意以下四个前提:

  1. 互斥性。在恣意时候,只有一个客户端能持有锁
  2. 不会发送命锁。纵然一个客户端持有锁的时代瓦解而没有主动开释锁,也必要担保后续其他客户端可以或许加锁乐成
  3. 加锁息争锁必需是统一个客户端,客户端本身不能把别人加的锁给开释了。
  4. 容错性。只要大部门的Redis节点正常运行,客户端就可以举办加锁息争锁操纵。

三、Redis实现漫衍式锁的错误姿势

3.1 加锁错误姿势

在讲授行使Redis实现漫衍式锁的正确姿势之前,我们有须要来看下错误实现方法。

起首,为了担保互斥性和不会发送命锁2个前提,以是我们在加锁操纵的时辰,必要行使SETNX指令来担保互斥性——只有一个客户端可以或许持有锁。为了担保不会发送命锁,必要给锁加一个逾期时刻,这样就可以担保纵然持有锁的客户端时代瓦解了也不会一向不开释锁。

为了担保这2个前提,有些人错误的实现会用如下代码来实现加锁操纵:

  1. /** 
  2.      * 实现加锁的错误姿势 
  3.      * @param jedis 
  4.      * @param lockKey 
  5.      * @param requestId 
  6.      * @param expireTime 
  7.      */ 
  8.     public static void wrongGetLock1(Jedis jedis, String lockKey, String requestId, int expireTime) { 
  9.         Long result = jedis.setnx(lockKey, requestId); 
  10.         if (result == 1) { 
  11.             // 若在这里措施溘然瓦解,则无法配置逾期时刻,将发存亡锁 
  12.             jedis.expire(lockKey, expireTime); 
  13.         } 
  14.     } 

也许一些初学者还没看出以上实现加锁操纵的错误缘故起因。这样我们表明下。setnx 和expire是两条Redis指令,不具备原子性,假如措施在执行完setnx之后溘然瓦解,导致没有配置锁的逾期时刻,从而就导致死锁了。由于这个客户端持有的全部不会被其他客户端开释,持有锁的客户端又瓦解了,也不会主动开释。从而该锁永久不会开释,导致其他客户端也得到不能锁。从而其他客户端一向阻塞。以是针对该代码正确姿势应该担保setnx和expire原子性。

实现加锁操纵的错误姿势2。详细实现如下代码所示

  1. /** 
  2.      * 实现加锁的错误姿势2 
  3.      * @param jedis 
  4.      * @param lockKey 
  5.      * @param expireTime 
  6.      * @return 
  7.      */ 
  8.     public static boolean wrongGetLock2(Jedis jedis, String lockKey, int expireTime) { 
  9.         long expires = System.currentTimeMillis() + expireTime; 
  10.         String expiresStr = String.valueOf(expires); 
  11.         // 假如当前锁不存在,返回加锁乐成 
  12.         if (jedis.setnx(lockKey, expiresStr) == 1) { 
  13.             return true; 
  14.         } 
  15.  
  16.         // 假如锁存在,获取锁的逾期时刻 
  17.         String currentValueStr = jedis.get(lockKey); 
  18.         if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { 
  19.             // 锁已逾期,获取上一个锁的逾期时刻,并配置此刻锁的逾期时刻 
  20.             String oldValueStr = jedis.getSet(lockKey, expiresStr); 
  21.             if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { 
  22.                 // 思量多线程并发的环境,只有一个线程的配置值和当前值沟通,它才有权力加锁 
  23.                 return true; 
  24.             } 
  25.         } 
  26.         // 其他环境,一致返回加锁失败 
  27.         return false; 
  28.     } 

这个加锁操纵咋一看没有短处对吧。那以上这段代码的题目短处出在那边呢?

1. 因为客户端本身天生逾期时刻,以是必要逼迫要求漫衍式情形下全部客户端的时刻必需同步。

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读