分布式鎖除了 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; } }
