• Redis Lock 分布式锁实现


    1  源码

    package com.yx.redis.jedis;
    
    import lombok.extern.slf4j.Slf4j;
    
    import java.util.Collections;
    
    /**
     * @Auther: yx
     * @Date: 2019-05-05 16:13
     * @Description: DistributedLocker
     */
    @Slf4j
    public class JedisDistributedLocker {
        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";
        private static final String UNLOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        private static final int RETRY_TIME = 100;
    
        private JedisTemplate jedisTemplate;
    
        public JedisDistributedLocker(JedisTemplate jedisTemplate) {
            this.jedisTemplate = jedisTemplate;
        }
    
        /**
         * 尝试获取分布式锁
         * @param lockKey 锁
         * @param requestId 请求标识
         * @param expireTime 超期时间
         * @return 是否获取成功
         */
        public boolean lock(String lockKey, String requestId, int expireTime) {
    
            String result = jedisTemplate.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
    
            if (LOCK_SUCCESS.equals(result)) {
                return true;
            }
    
            return false;
        }
    
        /**
         * 加锁
         * @param lockKey
         * @param waitTime    等待时间
         * @param expireTime 强制锁释放时间
         * @return
         */
        public boolean tryLock(String lockKey, String requestId, int waitTime, int expireTime) {
            int alreadyWaitTime = 0;
            while (waitTime > alreadyWaitTime) {
                if (lock(lockKey, requestId, expireTime)) {
                    return true;
                } else {
                    try {
                        Thread.sleep(RETRY_TIME);
                    } catch (InterruptedException e) {
                        log.warn(e.getMessage(), e);
    
                        return false;
                    }
                }
    
                alreadyWaitTime += RETRY_TIME;
            }
    
            return false;
        }
    
        /**
         * 释放分布式锁
         * @param lockKey 锁
         * @param requestId 请求标识
         * @return 是否释放成功
         */
        public boolean unlock(String lockKey, String requestId) {
    
            Object result = jedisTemplate.eval(UNLOCK_SCRIPT, Collections.singletonList(lockKey), Collections.singletonList(requestId));
    
            if (RELEASE_SUCCESS.equals(result)) {
                return true;
            }
            return false;
    
        }
    }

    2  加锁命令说明

    SET key value [EX seconds] [PX milliseconds] [NX|XX]

    将字符串值 value 关联到 key

    如果 key 已经持有其他值, SET 就覆写旧值,无视类型。

    对于某个原本带有生存时间(TTL)的键来说, 当 SET 命令成功在这个键上执行时, 这个键原有的 TTL 将被清除。

    可选参数

    从 Redis 2.6.12 版本开始, SET 命令的行为可以通过一系列参数来修改:

      • EX second :设置键的过期时间为 second 秒。 SET key value EX second 效果等同于 SETEX key second value
      • PX millisecond :设置键的过期时间为 millisecond 毫秒。 SET key value PX millisecond 效果等同于 PSETEX key millisecond value
      • NX :只在键不存在时,才对键进行设置操作。 SET key value NX 效果等同于 SETNX key value
      • XX :只在键已经存在时,才对键进行设置操作。
  • 相关阅读:
    Bufferedreader和BufferedWriter(带缓存的输入输出)
    FileReader和FileWriter
    Map接口的类实现
    Map接口
    Set集合
    List接口的实现类
    获取文本框或密码框中的内容
    ADTS (zz)
    初级美语 L003:My Family 解析
    初级美语 L001:Self Introduction 解析
  • 原文地址:https://www.cnblogs.com/yx88/p/10900051.html
Copyright © 2020-2023  润新知