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 :只在键已经存在时,才对键进行设置操作。

猜你喜欢

转载自www.cnblogs.com/yx88/p/10900051.html