分布式锁的奥义
占坑一般使用setnx指令,只允许被一个客户端占坑,先来先占,用完了再del
但是如果逻辑执行到中间除了异常,导致del操作没有被调用,就会陷入死锁,锁得不到释放
可以在拿到锁之后,给锁加上一个过期时间
但是如果在setnx和expire之间服务器进程突然关了,导致expire得不到执行,也会造成死锁
根源setnx和expire不是原子指令
Redis2.8中对set进行扩展,使得setnx和expire指令可以一起执行,解决了分布式锁的乱象
set lock:codehole true ex 5 nx
超时问题
如果在加锁和释放锁之间的逻辑执行得过长,超出了锁的超时限制,就会出现问题。
避免这个问题,Redis分布式锁不要用于较长时间的任务
方案:将set指令的value参数设置为一个随机数,释放锁实现匹配一下随机数是否一致,然后再删除key,确保当前线程占有的锁不会被其他线程释放,除非这个琐是因为过期而被服务器自动释放
但是匹配value和删除key不是一个原子操作,需要用Lua脚本处理
可重入性
可重入性是指线程在持有锁的情况下再次请求加锁,如果一个锁支持同一个线程的多次加锁,那么这个锁是可重入的
public class RedisWithReentrantLock {
private ThreadLocal<Map<String, Integer>> lockers = new ThreadLocal<Map<String, Integer>>();//ThreadLocal加计数器
private Jedis jedis;
public RedisWithReentrantLock(Jedis jedis){
this.jedis = jedis;
}
private boolean _lock(String key){
return jedis.set(key, "", "nx", "ex", 5L) != null;
}
private void _unlock(String key){
jedis.del(key);
}
private Map<String, Integer> currentLockers(){
Map<String, Integer> refs = lockers.get();
if(refs != null){
return refs;
}
lockers.set(new HashMap<String, Integer>());
return lockers.get();
}
public boolean lock(String key){
Map<String, Integer> refs = currentLockers();
Integer refCnt =refs.get(key);
if(refCnt != null){
refs.put(key,refCnt + 1);//+1
return true;
}
boolean ok = this._lock(key);
if(!ok){
return false;
}
refs.put(key, 1);
return true;
}
public boolean unlock(String key){
Map<String, Integer> refs = currentLockers();
Integer refCnt = refs.get(key);
if(refCnt == null){
return false;
}
refCnt -= 1;
if(refCnt > 0){
refs.put(key, refCnt);//-1
} else {
refs.remove(key);
this._unlock(key);
}
return true;
}
public static void main(String[] args) {
//连接redis服务器(在这里是连接本地的)
Jedis jedis = new Jedis("127.0.0.1", 6379);
//权限认证
//jedis.auth("");
System.out.println("连接服务成功");
RedisWithReentrantLock redis = new RedisWithReentrantLock(jedis);
System.out.println(redis.lock("codehole"));
System.out.println(redis.lock("codehole"));
System.out.println(redis.unlock("codehole"));
System.out.println(redis.unlock("codehole"));
}
}
基于ThreadLocal和引用计数