public class Lock {
public static void main(String[] args) {
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new RetryOneTime(1000));
client.start();
InterProcessMutex lock = new InterProcessMutex(client, "/d-lock");
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println("尝试获取锁。。。");
try {
lock.acquire();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("获得锁");
try {
System.out.println("执行中。。。。。。。。。。");
Thread.sleep(1000 * 60 * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("执行完,释放锁");
try {
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("释放成功");
}).start();
}
}
}
查看lock.acquire()方法, acquire支持同线程重入,获取不到锁会一直阻塞。
/**
* Acquire the mutex - blocking until it's available. Note: the same thread
* can call acquire re-entrantly. Each call to acquire must be balanced by a call
* to {@link #release()}
*
* @throws Exception ZK errors, connection interruptions
*/
@Override
public void acquire() throws Exception
{
if ( !internalLock(-1, null) )
{
throw new IOException("Lost connection while trying to acquire lock: " + basePath);
}
}
查看internallock方法,处理重入并获取锁。
private boolean internalLock(long time, TimeUnit unit) throws Exception
{
Thread currentThread = Thread.currentThread();
LockData lockData = threadData.get(currentThread);
if ( lockData != null )
{
// 重入
lockData.lockCount.incrementAndGet();
return true;
}
//尝试获取锁
String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
if ( lockPath != null )
{
LockData newLockData = new LockData(currentThread, lockPath);
threadData.put(currentThread, newLockData);
return true;
}
return false;
}
查看internals.attempLock方法
String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception
{
//记录当前时间
final long startMillis = System.currentTimeMillis();
//记录锁等待时间
final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;
//临时顺序节点的data
final byte[] localLockNodeBytes = (revocable.get() != null) ? new byte[0] : lockNodeBytes;
//节点不存在重试次数
int retryCount = 0;
//临时顺序节点path
String ourPath = null;
//当前path是否获取到锁
boolean hasTheLock = false;
//flag
boolean isDone = false;
while ( !isDone )
{
isDone = true;
try
{
//创建临时顺序节点
ourPath = driver.createsTheLock(client, path, localLockNodeBytes);
//获取锁
hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);
}
catch ( KeeperException.NoNodeException e )
{
// gets thrown by StandardLockInternalsDriver when it can't find the lock node
// this can happen when the session expires, etc. So, if the retry allows, just try it all again
if ( client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper()) )
{
isDone = false;
}
else
{
throw e;
}
}
}
//获取到锁,返回path
if ( hasTheLock )
{
return ourPath;
}
return null;
}
查看createsTheLock方法
@Override
public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception
{
String ourPath;
if ( lockNodeBytes != null )
{
ourPath = client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, lockNodeBytes);
}
else
{
ourPath = client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
}
return ourPath;
}
查看internalLockLoop方法
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).forPath(ourPath);
}
//自旋,直到获取到锁
while ( (client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock )
{
//获取到所有的子节点并排序
List children = getSortedChildren();
//当前节点名称
String sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash
//判断是否可以拿到锁,前一个path:当前path是否获取到锁
PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
//如果拿到锁,返回
if ( predicateResults.getsTheLock() )
{
haveTheLock = true;
}
else
{
//前一个path
String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
synchronized(this)
{
try
{
// use getData() instead of exists() to avoid leaving unneeded watchers which is a type of resource leak
//增加watcher,实现就是notifyAll,如果节点不存在抛出节点不存在异常
client.getData().usingWatcher(watcher).forPath(previousSequencePath);
//如果有等待时间
if ( millisToWait != null )
{
millisToWait -= (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if ( millisToWait <= 0 )
{
doDelete = true; // timed out - delete our node
break;
}
wait(millisToWait);
}
else
{
//无限等待
wait();
}
}
catch ( KeeperException.NoNodeException e )
{
// it has been deleted (i.e. lock released). Try to acquire again
}
}
}
}
}
catch ( Exception e )
{
doDelete = true;
throw e;
}
finally
{
if ( doDelete )
{
deleteOurPath(ourPath);
}
}
return haveTheLock;
}