分布式锁
分布式锁有多种实现方式,比如数据库,Redis都可以实现分布式锁,作为分布式协同工具zookeeper,当然也有着标准的实现方式。
设计思路
- 每个客户端往/Locks下创建l临时有序节点/Locks/Lock_,创建成功后/Locks下面会有每个客户端对应的节点。如/Locks/Lock_000000001
- 客户端获取/Locks下子节点,并进行排序,判断排在最前面的是否为自己,如果自己的锁节点排在第一位,代表获取锁成功
- 如果自己的锁节点不在第一位,则监听自己前一位的锁节点。例如,自己锁节点Lock_000000002,那么监听Lock_0000000001
- 当前一位锁节点(Lock_0000000001)对应的客户端执行完成,释放了锁,将会触发监听客户端
- 监听客户端重新执行第2步逻辑,判断自己是否获得了锁
java案例
private void createLock() throws Exception{
//判断节点是否存在
Stat stat = zooKeeper.exists(LOCK_ROOT_PATH,false);
if(stat == null){
zooKeeper.create(LOCK_ROOT_PATH,new byte[0],ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}
//创建临时有序节点
lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME,new byte[0],ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}
Watcher watch = new Watcher(){
public void process(){
if(event.getType == Event,EventType.NodeDeleted){
synchronized(this){
notifyAll();
}
}
}
}
private void attemptLock() throws Exception{
//获取Locks节点下所有孩子节点
List<String>list = zooKeeper.getChildren(LOCK_ROOT_PATH,false);
//对节点进行排序
Collection.sort(list);
int index = list.indexOf(lockPath.subString(LOCK_ROOT_PATH.length() + 1));
if(index == 0){
System.out.println("获取锁成功");
}else {
//上一个节点路径
String path = list.get(index-1);
zooKeeper.exists(LOCK_ROOT_PATH + "/" + path,wathcer);
if(stat == nukk){
attemptLock();
}else{
synchronized(watcher){
watcher.wait();
}
attemptLock();
}
}
}
public void releaseLock() throws Exception{
zooKeeper.delete(this.lockPath,-1);
zooKeeper.close();
System,out.println("锁已经释放" + this.lockPath);
}