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

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

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

Redis漫衍式锁实现的正确姿势的实当代码:

  1. public interface DistributedLock { 
  2.     /** 
  3.      * 获取锁 
  4.      * @author zhi.li 
  5.      * @return 锁标识 
  6.      */ 
  7.     String acquire(); 
  8.  
  9.     /** 
  10.      * 开释锁 
  11.      * @author zhi.li 
  12.      * @param indentifier 
  13.      * @return 
  14.      */ 
  15.     boolean release(String indentifier); 
  16.  
  17. /** 
  18.  * @author zhi.li 
  19.  * @Description 
  20.  * @created 2019/1/1 20:32 
  21.  */ 
  22. @Slf4j 
  23. public class RedisDistributedLock implements DistributedLock{ 
  24.  
  25.     private static final String LOCK_SUCCESS = "OK"; 
  26.     private static final Long RELEASE_SUCCESS = 1L; 
  27.     private static final String SET_IF_NOT_EXIST = "NX"; 
  28.     private static final String SET_WITH_EXPIRE_TIME = "PX"; 
  29.  
  30.     /** 
  31.      * redis 客户端 
  32.      */ 
  33.     private Jedis jedis; 
  34.  
  35.     /** 
  36.      * 漫衍式锁的键值 
  37.      */ 
  38.     private String lockKey; 
  39.  
  40.     /** 
  41.      * 锁的超时时刻 10s 
  42.      */ 
  43.     int expireTime = 10 * 1000; 
  44.  
  45.     /** 
  46.      * 锁守候,防备线程饥饿 
  47.      */ 
  48.     int acquireTimeout  = 1 * 1000; 
  49.  
  50.     /** 
  51.      * 获取指定键值的锁 
  52.      * @param jedis jedis Redis客户端 
  53.      * @param lockKey 锁的键值 
  54.      */ 
  55.     public RedisDistributedLock(Jedis jedis, String lockKey) { 
  56.         this.jedis = jedis; 
  57.         this.lockKey = lockKey; 
  58.     } 
  59.  
  60.     /** 
  61.      * 获取指定键值的锁,同时配置获取锁超时时刻 
  62.      * @param jedis jedis Redis客户端 
  63.      * @param lockKey 锁的键值 
  64.      * @param acquireTimeout 获取锁超时时刻 
  65.      */ 
  66.     public RedisDistributedLock(Jedis jedis,String lockKey, int acquireTimeout) { 
  67.         this.jedis = jedis; 
  68.         this.lockKey = lockKey; 
  69.         this.acquireTimeout = acquireTimeout; 
  70.     } 
  71.  
  72.     /** 
  73.      * 获取指定键值的锁,同时配置获取锁超时时刻和锁逾期时刻 
  74.      * @param jedis jedis Redis客户端 
  75.      * @param lockKey 锁的键值 
  76.      * @param acquireTimeout 获取锁超时时刻 
  77.      * @param expireTime 锁失效时刻 
  78.      */ 
  79.     public RedisDistributedLock(Jedis jedis, String lockKey, int acquireTimeout, int expireTime) { 
  80.         this.jedis = jedis; 
  81.         this.lockKey = lockKey; 
  82.         this.acquireTimeout = acquireTimeout; 
  83.         this.expireTime = expireTime; 
  84.     } 
  85.  
  86.     @Override 
  87.     public String acquire() { 
  88.         try { 
  89.             // 获取锁的超时时刻,高出这个时刻则放弃获取锁 
  90.             long end = System.currentTimeMillis() + acquireTimeout; 
  91.             // 随机天生一个value 
  92.             String requireToken = UUID.randomUUID().toString(); 
  93.             while (System.currentTimeMillis() < end) { 
  94.                 String result = jedis.set(lockKey, requireToken, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); 
  95.                 if (LOCK_SUCCESS.equals(result)) { 
  96.                     return requireToken; 
  97.                 } 
  98.                 try { 
  99.                     Thread.sleep(100); 
  100.                 } catch (InterruptedException e) { 
  101.                     Thread.currentThread().interrupt(); 
  102.                 } 
  103.             } 
  104.         } catch (Exception e) { 
  105.             log.error("acquire lock due to error", e); 
  106.         } 
  107.  
  108.         return null; 
  109.     } 
  110.  
  111.     @Override 
  112.     public boolean release(String identify) { 
  113.   if(identify == null){ 
  114.             return false; 
  115.         } 
  116.  
  117.         String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; 
  118.         Object result = new Object(); 
  119.         try { 
  120.             result = jedis.eval(script, Collections.singletonList(lockKey), 
  121.                 Collections.singletonList(identify)); 
  122.         if (RELEASE_SUCCESS.equals(result)) { 
  123.             log.info("release lock success, requestToken:{}", identify); 
  124.             return true; 
  125.         }}catch (Exception e){ 
  126.             log.error("release lock due to error",e); 
  127.         }finally { 
  128.             if(jedis != null){ 
  129.                 jedis.close(); 
  130.             } 
  131.         } 
  132.  
  133.         log.info("release lock failed, requestToken:{}, result:{}", identify, result); 
  134.         return false; 
  135.     } 
下面就以秒杀库存数目为场景,测试下上面实现的漫衍式锁的结果。详细测试代码如下:
  1. public class RedisDistributedLockTest { 
  2.     static int n = 500; 
  3.     public static void secskill() { 
  4.         System.out.println(--n); 
  5.     } 
  6.  
  7.     public static void main(String[] args) { 
  8.         Runnable runnable = () -> { 
  9.             RedisDistributedLock lock = null; 
  10.             String unLockIdentify = null; 
  11.             try { 
  12.                 Jedis conn = new Jedis("127.0.0.1",6379); 
  13.                 lock = new RedisDistributedLock(conn, "test1"); 
  14.                 unLockIdentify = lock.acquire(); 
  15.                 System.out.println(Thread.currentThread().getName() + "正在运行"); 
  16.                 在此我向各人保举一个架构进修交换圈:830478757 辅佐打破瓶颈 晋升思想手段 
  17.                 secskill(); 
  18.             } finally { 
  19.                 if (lock != null) { 
  20.                     lock.release(unLockIdentify); 
  21.                 } 
  22.             } 
  23.         }; 
  24.  
  25.         for (int i = 0; i < 10; i++) { 
  26.             Thread t = new Thread(runnable); 
  27.             t.start(); 
  28.         } 
  29.     } 

运行结果如下图所示。从图中可以看出,统一个资源在统一个时候只能被一个线程获取,从而担保了库存数目N的递减是次序的。

五、总结

(编辑:湖南网)

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

热点阅读