分布式锁的实现
基于Redis的锁
- 使用原子的set命令的nx 、ex参数设置过期时间和一个预定的值
- 设置成功后,即获取到锁,执行业务操作,否则没有获取到锁
- 获取锁的值,并比较预定的值是否和当前值相同,相同则可以删除,否则不能删除
以下代码基于Lua脚本实现
/**
*定义用到的Lua脚本
*/
final String LOCK_SCRIPT_STR = "if redis.call('set',KEYS[1],ARGV[1],'EX',ARGV[2],'NX') then return 1 else return 0 end";
final String UNLOCK_SCRIPT_STR = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
String uuid=UUID.randomUUID().toString();
try {
Object evalsha = jedis.evalsha(jedis.scriptLoad(LOCK_SCRIPT_STR), Arrays.asList("key"), Arrays.asList(uuid, "1000"));
if("1".equals(evalsha)){
System.out.println("执行业务逻辑");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
jedis.evalsha(jedis.scriptLoad(UNLOCK_SCRIPT_STR), Arrays.asList("key"), Arrays.asList(uuid));
}
基于zookeeper的锁
1.客户端在获取锁时,会在一个目录节点下创建一个临时节点,这个临时节点是有序号的,如:/lock/lock-0000000,/lock/lock-0000001
2.客户端获取目录节点下的所有子节点(lock-0000000,lock-0000001...),判断自己创建的节点是否为子节点列表最小的那个子节点
3.如果是,则认为当前客户端获取到锁,否则监听前一个子节点的删除事件
4. 执行业务代码
5.删除自己创建的子节点,并通知后一个监听器
以下是基于Curator实现的分布式锁
//引入maven
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
实现代码
try {
//创建zookeeper的客户端
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", retryPolicy);
client.start();
//创建分布式锁, 锁空间的根节点路径为/curator/lock
InterProcessMutex mutex = new InterProcessMutex(client, "/curator/lock");
mutex.acquire();
//获得了锁, 进行业务流程
System.out.println("Enter mutex");
} catch (Exception e) {
e.printStackTrace();
}finally {
//完成业务流程, 释放锁
mutex.release();
//关闭客户端
client.close();
}