ZooKeeper客户端 Curator三
简介
- Curator作为客户端实现了 ZooKeeper的核心接口封装. 大幅度降低了 ZooKeeper的使用复杂度
- http://curator.apache.org
Curator锁接口源码分析
实现可重入互斥锁, 有两种方法
- InterProcessMutex - boolean acquire(long time, TimeUnit unit), 可设置过期时间, 当业务处理或系统故障设定的时间内未执行解锁命令时, 将自动释放锁
- InterProcessMutex - void acquire(), 无参方法默认过期时间为 -1, 也就是除客户端会话失效以外, 执行过程中是不会自动释放锁
LockInternals类
private boolean internalLock(long time, TimeUnit unit) throws Exception {
Thread currentThread = Thread.currentThread();
// 获得当前线程的锁
InterProcessMutex.LockData lockData = (InterProcessMutex.LockData)this.threadData.get(currentThread);
if (lockData != null) {
// 如果当前线程已有锁, 将重入
lockData.lockCount.incrementAndGet();
return true;
} else {
// 如果当前线程没有锁, 在此尝试获取锁, 成功就会返回节点路径
String lockPath = this.internals.attemptLock(time, unit, this.getLockNodeBytes());
if (lockPath != null) {
// 将当前线程的锁对象信息保存起来
InterProcessMutex.LockData newLockData = new InterProcessMutex.LockData(currentThread, lockPath);
this.threadData.put(currentThread, newLockData);
return true;
} else {
return false;
}
}
}
String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception {
long startMillis = System.currentTimeMillis();
Long millisToWait = unit != null ? unit.toMillis(time) : null;
byte[] localLockNodeBytes = this.revocable.get() != null ? new byte[0] : lockNodeBytes;
int retryCount = 0;
String ourPath = null;
boolean hasTheLock = false;
boolean isDone = false;
while(!isDone) {
isDone = true;
try {
// 在当前节点下, 创建临时有序节点
ourPath = this.driver.createsTheLock(this.client, this.path, localLockNodeBytes);
// 判断是不是序号最小的节点, 如是就返回 true, 否则阻塞等待
hasTheLock = this.internalLockLoop(startMillis, millisToWait, ourPath);
} catch (NoNodeException var14) {
if (!this.client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper())) {
throw var14;
}
isDone = false;
}
}
return hasTheLock ? ourPath : null;
}
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception {
boolean haveTheLock = false;
boolean doDelete = false;
try {
if (this.revocable.get() != null) {
((BackgroundPathable)this.client.getData().usingWatcher(this.revocableWatcher)).forPath(ourPath);
}
while(this.client.getState() == CuratorFrameworkState.STARTED && !haveTheLock) {
// 获取所有子节点
List<String> children = this.getSortedChildren();
// 获取当前的有序节点路径
String sequenceNodeName = ourPath.substring(this.basePath.length() + 1);
// 判断给当前节点, 要加锁还是给比当前节点小一的节点加监控
PredicateResults predicateResults = this.driver.getsTheLock(this.client, children, sequenceNodeName, this.maxLeases);
// true意思为加锁成功
if (predicateResults.getsTheLock()) {
haveTheLock = true;
} else {
String previousSequencePath = this.basePath + "/" + predicateResults.getPathToWatch();
synchronized(this) {
try {
// 给比当前节点小一的节点加监控
((BackgroundPathable)this.client.getData().usingWatcher(this.watcher)).forPath(previousSequencePath);
if (millisToWait == null) {
// 如空则, 一直阻塞等待
this.wait();
} else {
millisToWait = millisToWait - (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if (millisToWait > 0L) {
// 未过期, 一直阻塞等待
this.wait(millisToWait);
} else {
// 过期删除
doDelete = true;
break;
}
}
} catch (NoNodeException var19) {
;
}
}
}
}
} catch (Exception var21) {
ThreadUtils.checkInterrupted(var21);
doDelete = true;
throw var21;
} finally {
if (doDelete) {
// 如果抛异常或过期, 都将会删除临时节点
this.deleteOurPath(ourPath);
}
}
return haveTheLock;
}
public static List<String> getSortedChildren(CuratorFramework client, String basePath, final String lockName, final LockInternalsSorter sorter) throws Exception {
// 获取节点下的所有有序节点(自动排序)
List<String> children = (List)client.getChildren().forPath(basePath);
List<String> sortedList = Lists.newArrayList(children);
Collections.sort(sortedList, new Comparator<String>() {
public int compare(String lhs, String rhs) {
return sorter.fixForSorting(lhs, lockName).compareTo(sorter.fixForSorting(rhs, lockName));
}
});
return sortedList;
}
List<String> getSortedChildren() throws Exception {
return getSortedChildren(this.client, this.basePath, this.lockName, this.driver);
}
private void deleteOurPath(String ourPath) throws Exception {
try {
// 删除节点
((ChildrenDeletable)this.client.delete().guaranteed()).forPath(ourPath);
} catch (NoNodeException var3) {
;
}
}
final void releaseLock(String lockPath) throws Exception {
// 删除监听
this.client.removeWatchers();
this.revocable.set((Object)null);
// 删除节点
this.deleteOurPath(lockPath);
}
StandardLockInternalsDriver implements LockInternalsDriver
public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception {
String ourPath;
// 在指定路径内, 创建一个临时有序节点
if (lockNodeBytes != null) {
ourPath = (String)((ACLBackgroundPathAndBytesable)client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)).forPath(path, lockNodeBytes);
} else {
ourPath = (String)((ACLBackgroundPathAndBytesable)client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)).forPath(path);
}
return ourPath;
}
public PredicateResults getsTheLock(CuratorFramework client, List<String> children, String sequenceNodeName, int maxLeases) throws Exception {
// 通过当前节点路径, 从有序节点列表中获取索引
int ourIndex = children.indexOf(sequenceNodeName);
validateOurIndex(sequenceNodeName, ourIndex);
// 当获取到的索引为0时(ourIndex=0), 意思是当前的节点是最小的. maxLeases默认是1
boolean getsTheLock = ourIndex < maxLeases;
// 如以上条件成立, 意思是当前节点获取到锁了, 否者给比自己小一的节点加监控
String pathToWatch = getsTheLock ? null : (String)children.get(ourIndex - maxLeases);
return new PredicateResults(pathToWatch, getsTheLock);
}
InterProcessMutex implements InterProcessLock, Revocable
public void release() throws Exception {
Thread currentThread = Thread.currentThread();
InterProcessMutex.LockData lockData = (InterProcessMutex.LockData)this.threadData.get(currentThread);
// 如果当前线程没有持有锁,不能释放报异常
if (lockData == null) {
throw new IllegalMonitorStateException("You do not own the lock: " + this.basePath);
} else {
// 或重入锁计数减一, 之后如还是大于0, 不能释放. 直到完成所有重入锁
int newLockCount = lockData.lockCount.decrementAndGet();
if (newLockCount <= 0) {
if (newLockCount < 0) {
throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + this.basePath);
} else {
try {
this.internals.releaseLock(lockData.lockPath);
} finally {
this.threadData.remove(currentThread);
}
}
}
}
}
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!