Redis使用場景(二)分布式鎖詳盡版


分布式鎖除了 redis實現外還有:數據庫樂觀鎖和zookeeper效率有限。

分布式鎖要滿足以下條件:

  互斥性:確保同一時刻只有一個客戶端持有鎖。

  不死鎖:一個客戶端持有鎖因斷網,崩潰等原因失聯了,仍可讓下一個人得到鎖。

  容錯性:大部分redis節點可用,客戶端就可以加鎖解鎖。

  統一性:加鎖和解鎖必須為同一客戶端。  

首先引包

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

實現:

public class RedisTool {
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_NOT_EXIST = "NX";
    private static final String SET_EXPIRE_TIME = "PX";
    private static final Long RELEASE_SUCCESS = 1L;
    //加鎖
    public static boolean addLock(Jedis jedis, String lockKey, String userId, int expireTime) {
        //參數解析:
        //1.key 做鎖
        //2.value:userId 用用戶id 來標識鎖是誰的
        //3.nx xx:兩種選擇:NX:key不存在才set值 XX:key存在時才set值。
        //4.ex px:兩種選擇:EX:seconds 秒 PX:millSeconds毫秒
        //5.設置過期時間
        String result = jedis.set(lockKey, userId, SET_NOT_EXIST, SET_EXPIRE_TIME, expireTime);
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
    //解鎖
    public static boolean goodByeLock(Jedis jedis, String lockKey, String requestId) {
        //這種寫法會出問題
        //String result = jedis.get(lockKey);
        //如果a鎖先超時了 這時b獲取到了鎖,a在解鎖時會將b的鎖接觸
//        if (result.equals(requestId)) {//            jedis.del(lockKey);
//        }
        //這種寫法比較正確
        String script = "if redis.call('get', KEYS[1]) == args[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;
    }
}


免責聲明!

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



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