Redis分布式锁实现的正确姿势的实现代码:
- public interface DistributedLock {
- /**
- * 获取锁
- * @author zhi.li
- * @return 锁标识
- */
- String acquire();
-
- /**
- * 释放锁
- * @author zhi.li
- * @param indentifier
- * @return
- */
- boolean release(String indentifier);
- }
-
- /**
- * @author zhi.li
- * @Description
- * @created 2019/1/1 20:32
- */
- @Slf4j
- public class RedisDistributedLock implements DistributedLock{
-
- private static final String LOCK_SUCCESS = "OK";
- private static final Long RELEASE_SUCCESS = 1L;
- private static final String SET_IF_NOT_EXIST = "NX";
- private static final String SET_WITH_EXPIRE_TIME = "PX";
-
- /**
- * redis 客户端
- */
- private Jedis jedis;
-
- /**
- * 分布式锁的键值
- */
- private String lockKey;
-
- /**
- * 锁的超时时间 10s
- */
- int expireTime = 10 * 1000;
-
- /**
- * 锁等待,防止线程饥饿
- */
- int acquireTimeout = 1 * 1000;
-
- /**
- * 获取指定键值的锁
- * @param jedis jedis Redis客户端
- * @param lockKey 锁的键值
- */
- public RedisDistributedLock(Jedis jedis, String lockKey) {
- this.jedis = jedis;
- this.lockKey = lockKey;
- }
-
- /**
- * 获取指定键值的锁,同时设置获取锁超时时间
- * @param jedis jedis Redis客户端
- * @param lockKey 锁的键值
- * @param acquireTimeout 获取锁超时时间
- */
- public RedisDistributedLock(Jedis jedis,String lockKey, int acquireTimeout) {
- this.jedis = jedis;
- this.lockKey = lockKey;
- this.acquireTimeout = acquireTimeout;
- }
-
- /**
- * 获取指定键值的锁,同时设置获取锁超时时间和锁过期时间
- * @param jedis jedis Redis客户端
- * @param lockKey 锁的键值
- * @param acquireTimeout 获取锁超时时间
- * @param expireTime 锁失效时间
- */
- public RedisDistributedLock(Jedis jedis, String lockKey, int acquireTimeout, int expireTime) {
- this.jedis = jedis;
- this.lockKey = lockKey;
- this.acquireTimeout = acquireTimeout;
- this.expireTime = expireTime;
- }
-
- @Override
- public String acquire() {
- try {
- // 获取锁的超时时间,超过这个时间则放弃获取锁
- long end = System.currentTimeMillis() + acquireTimeout;
- // 随机生成一个value
- String requireToken = UUID.randomUUID().toString();
- while (System.currentTimeMillis() < end) {
- String result = jedis.set(lockKey, requireToken, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
- if (LOCK_SUCCESS.equals(result)) {
- return requireToken;
- }
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- } catch (Exception e) {
- log.error("acquire lock due to error", e);
- }
-
- return null;
- }
-
- @Override
- public boolean release(String identify) {
- if(identify == null){
- return false;
- }
-
- String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
- Object result = new Object();
- try {
- result = jedis.eval(script, Collections.singletonList(lockKey),
- Collections.singletonList(identify));
- if (RELEASE_SUCCESS.equals(result)) {
- log.info("release lock success, requestToken:{}", identify);
- return true;
- }}catch (Exception e){
- log.error("release lock due to error",e);
- }finally {
- if(jedis != null){
- jedis.close();
- }
- }
-
- log.info("release lock failed, requestToken:{}, result:{}", identify, result);
- return false;
- }
- }
下面就以秒杀库存数量为场景,测试下上面实现的分布式锁的效果。具体测试代码如下:- public class RedisDistributedLockTest {
- static int n = 500;
- public static void secskill() {
- System.out.println(--n);
- }
-
- public static void main(String[] args) {
- Runnable runnable = () -> {
- RedisDistributedLock lock = null;
- String unLockIdentify = null;
- try {
- Jedis conn = new Jedis("127.0.0.1",6379);
- lock = new RedisDistributedLock(conn, "test1");
- unLockIdentify = lock.acquire();
- System.out.println(Thread.currentThread().getName() + "正在运行");
- 在此我向大家推荐一个架构学习交流圈:830478757 帮助突破瓶颈 提升思维能力
- secskill();
- } finally {
- if (lock != null) {
- lock.release(unLockIdentify);
- }
- }
- };
-
- for (int i = 0; i < 10; i++) {
- Thread t = new Thread(runnable);
- t.start();
- }
- }
- }
运行效果如下图所示。从图中可以看出,同一个资源在同一个时刻只能被一个线程获取,从而保证了库存数量N的递减是顺序的。
五、总结 (编辑:源码网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|