須要考慮的事情有:java
if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end
加鎖時:redis
建立一個隨機數,經過redis 提供的SET_IF_NOT_EXIST方式寫入這個key。並保存隨機數在線程上下文中緩存
private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; private static final String LOCK_SUCCESS = "OK"; private static ThreadLocal<String> ownerThreadLocal = new ThreadLocal<>();
源碼以下:網絡
在釋放鎖時: 併發
經過執行腳本的方式保證在併發下的一致性! 只有當線程上下文對象中的值與redis保存的值一致時,才能刪掉這個key,釋放成功。 這樣能夠保證加鎖與釋放鎖的都是這個線程!負載均衡
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 long UNLOCK_SUCCESS = 1L;
public boolean unlock(String key) { String ownerId = ownerThreadLocal.get(); if (StringUtils.isBlank(ownerId)) { return false; } try { List<String> keys = Collections.singletonList(key); //lua Long result = stringRedisTemplate.execute(new DefaultRedisScript<>(UNLOCK_SCRIPT, Long.class), keys, ownerId); if (UNLOCK_SUCCESS == result) { return true; } } catch (Exception e) { log.error("redis unlock fail", e); } finally { ownerThreadLocal.remove(); } return false; }