Curator实现分布式锁的基本原理-LockInternals.internalLockLoop

  • Post author:
  • Post category:其他


// 循环等待来激活分布式锁,实现锁的公平性 
private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception { 
	// 是否已经持有分布式锁 
	boolean haveTheLock = false; 
	// 是否需要删除子节点 
	boolean doDelete = false; 
	try { 
	if (revocable.get() != null) { 
		client.getData().usingWatcher(revocableWatcher).forPa
		th(ourPath); 
	} 

	while ((client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock) { 
		// 获取排序后的子节点列表 
		List<String> children = getSortedChildren(); 
		// 获取前面自己创建的临时顺序子节点的名称 
		String sequenceNodeName = ourPath.substring(basePath.length() + 1); 
		// 实现锁的公平性的核心逻辑,看下面的分析 
		PredicateResults predicateResults = driver.getsTheLock(client, children , sequenceNodeName , maxLeases); 
		if (predicateResults.getsTheLock()) { 
			// 获得了锁,中断循环,继续返回上层 
			haveTheLock = true; 
		} else { 
			// 没有获得到锁,监听上一临时顺序节点 
			String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch(); 
			synchronized (this) { 
				try { 
					// exists()会导致导致资源泄漏,因此exists()可以监听不存在的ZNode,因此采用getData() 
					// 上一临时顺序节点如果被删除,会唤醒当前线程继续竞争锁,正常情况下能直接获得锁,因为锁是公平的 
					client.getData().usingWatcher(watcher).forPath(previousSequencePath); 
					if (millisToWait != null) { 
						millisToWait -= (System.currentTimeMillis() - startMillis); 
						startMillis = System.currentTimeMillis(); 
						if (millisToWait <= 0) { 
							doDelete = true; // 获取锁超时,标记删除之前创建的临时顺序节点 
							break; 
						} 
						wait(millisToWait);// 等待被唤醒,限时等待 
					} else { 
						wait(); // 等待被唤醒,无限等待 
					} 
				} catch (KeeperException.NoNodeException e) { 
					// 容错处理,逻辑稍微有点绕,可跳过,不影响主逻辑的理解 
					// client.getData()可能调用时抛出NoNodeException,原因可能是锁被释放或会话过期(连接丢失)等 
					// 这里并没有做任何处理,因为外层是while循环,再次执行driver.getsTheLock时会调用validateOurIndex  
					// 此时会抛出NoNodeException,从而进入下面的catch和finally逻辑,重新抛出上层尝试重试获取锁并删除临时顺序节点 
				} 
			} 
		} 
	} 
	} catch (Exception e) { 
		ThreadUtils.checkInterrupted(e); 
		// 标记删除,在finally删除之前创建的临时顺序节点(后台不断尝试) 
		doDelete = true; 
		// 重新抛出,尝试重新获取锁 
		throw e; 
	} finally { 
		if (doDelete) { 
			deleteOurPath(ourPath); 
		} 
	} 
	return haveTheLock; 
}



版权声明:本文为Leon_Jinhai_Sun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。