网上到处都是分布式锁的代码,基本都是通过setNX 和 expire 

这两个不是原子操作,肯定会有问题,不乏好多人通过用setNX的value当做过期时间来弥补等等。但是好像都不太好,或者多少有点问题。

从一个大神那里得来的代码

 1 package com.abc.def.util;
 2 
 3 import redis.clients.jedis.Jedis;
 4 
 5 import java.util.Collections;
 6 
 7 public class RedisDistributedLock {
 8 
 9 
10     private static final String LOCK_SUCCESS = "OK";
11     private static final String SET_IF_NOT_EXIST = "NX";
12     private static final String SET_WITH_EXPIRE_TIME = "PX";
13     private static final Long RELEASE_SUCCESS = 1L;
14 
15     /**
16      * 尝试获取分布式锁
17      * @param jedis Redis客户端
18      * @param lockKey 锁
19      * @param requestId 请求标识
20      * @param expireTime 超期时间
21      * @return 是否获取成功
22      */
23     public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
24 
25         String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
26 
27         if (LOCK_SUCCESS.equals(result)) {
28             return true;
29         }
30         return false;
31 
32     }
33 
34     /**
35      * 释放分布式锁
36      * @param jedis Redis客户端
37      * @param lockKey 锁
38      * @param requestId 请求标识
39      * @return 是否释放成功
40      */
41     public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
42 
43         String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
44         Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
45 
46         if (RELEASE_SUCCESS.equals(result)) {
47             return true;
48         }
49         return false;
50 
51     }
52 
53 }

 

获取锁,通过一个条指令来获取并且同时设置超时。

另外,解锁是通过获取锁的时候设置的key  这个key应该是一个随机值 推荐使用 UUID 来生成。 这样只能解锁自己的锁

另外解锁操作用的lua脚本来执行,把三条语句集合成一个原子操作。

 

使用示例代码:

 1 while(true){
 2   String uuid = UUID.randomUUID().toString();
 4    boolean ret = lock.tryGetDistributedLock(redis,"NX_TEST", uuid, 5000);
 5    if(ret != false){
 6       //TODO 实现业务逻辑
 7       lock.releaseDistributedLock(redis,"NX_TEST", uuid);
 8       break;
 9    }else{
10       Thread.sleep(500);
11    }
12 }

 

这里,设置的5000(5秒)超时时间,这个时间一定要大于业务逻辑的执行时间,否则就没办法锁住了。。

参考博客 https://wudashan.cn/2017/10/23/Redis-Distributed-Lock-Implement/

 

PS: 哪位大神知道怎么从RedisTemplate 中获取 jedis ,RedisTemplate 并没有封装set 的相关函数。

 

posted on 2018-08-29 11:04  dspeeding  阅读(416)  评论(0编辑  收藏  举报