须要考虑的事情有: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; }