zookeeper分布式锁(六)针对创建节点的非“幂等”性操作提供了解决方案,下面,为了避免“羊群效应”,可以用以下的解决方案
execute()方法是前边介绍过的ZookeeperOperation类中的执行方法,在某一个进程申请“锁”的时候会执行这个方法,这个方法
返回“boolean”,用来判断申请成功或者失败,方法访问权限是“public”,没有参数。
方法首先判断当前节点存不存在,不存在的时候创建节点;
如果节点存在,取得lock服务根路径下的所有节点,获得比申请锁节点,即当前节点排序小的节点,如果不存在这样的集合lessThanMe,
那么申请锁成功,当前进程获得锁并执行业务回调callback,如果存在,获得lessThanMe最大的节点lessThanMe.last(),判断节点是否存在
,如果存在,在这个节点添加当前锁的监听(避免羊群效应),如果不存在,报异常。
代码如下:
public boolean execute() throws KeeperException, InterruptedException {
do {
if (id == null) {
long sessionId = zookeeper.getSessionId();
String prefix = "x-" + sessionId + "-";
// lets try look up the current ID if we failed
// in the middle of creating the znode
findPrefixInChildren(prefix, zookeeper, dir);
idName = new ZNodeName(id);
}
if (id != null) {
List<String> names = zookeeper.getChildren(dir, false);
if (names.isEmpty()) {
LOG.warn("No children in: " + dir + " when we've just " +
"created one! Lets recreate it...");
// lets force the recreation of the id
id = null;
} else {
// lets sort them explicitly (though they do seem to come back in order ususally :)
SortedSet<ZNodeName> sortedNames = new TreeSet<ZNodeName>();
for (String name : names) {
sortedNames.add(new ZNodeName(dir + "/" + name));
}
ownerId = sortedNames.first().getName();
SortedSet<ZNodeName> lessThanMe = sortedNames.headSet(idName);
if (!lessThanMe.isEmpty()) {
ZNodeName lastChildName = lessThanMe.last();
lastChildId = lastChildName.getName();
if (LOG.isDebugEnabled()) {
LOG.debug("watching less than me node: " + lastChildId);
}
Stat stat = zookeeper.exists(lastChildId, new LockWatcher());
if (stat != null) {
return Boolean.FALSE;
} else {
LOG.warn("Could not find the" +
" stats for less than me: " + lastChildName.getName());
}
} else {
if (isOwner()) {
if (callback != null) {
callback.lockAcquired();
}
return Boolean.TRUE;
}
}
}
}
}
while (id == null);
return Boolean.FALSE;
}