redis实现分布式锁:
public boolean tryLock(Jedis jedis, String keyLock, String requestId, String nx, String px, long expireTime){
try{
// set方法的nx和px参数保证加锁和设置超时时间的原子性
String result = jedis.set(keyLock, requestId, nx, px, expireTime);
return "OK".equals(result);
}finally{
jedis.close();
}
}
public void unLock(Jedis jedis, String keyLock, String requestId){
try{
Long releaseSuccess = 1L;
// eval命令执行lua代码的时候被当成一个命令去执行,保证了原子性
String script = "if jedis.call('get', KEYS[1]) == ARGV[1] then return jedis.call('del', KEYS[1]) else return0 end";
Object object = jedis.eval(script, Collections.singletonList(keyLock), Collections.singletonList(requestId));
return releaseSuccess.equals(object);
}finally{
jedis.close();
}
}
ZK是一个为分布式应用提供一致性服务的开源组件,内部是一个分层的文件系统目录树结构,规定同一个目录下只能存在唯一的文件名。
ZooKeeper实现分布式锁的步骤如下:
(1)创建一个目录mylock;
(2)线程A想获取锁就在mylock目录下创建临时顺序节点;
(3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
(4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
(5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁
InterProcessMutex是分布式锁的实现,acquire方法用于获取锁,release方法用于释放锁。
redis与ZK的对比:
ZK:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题,实现简单,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,但因为需要频繁的创建和删除节点,性能上不如Redis方式
Redis:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题,其实需要自己不断去尝试获取锁,可靠性没有ZK高但性能较高