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 :只在鍵已經存在時,才對鍵進行設置操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM