Apache Curator之InterProcessMutex源码分析(四)

上篇文章通过秒购的例子对InterProcessMutex锁有了初步认识,本文将通过对源码进行分析带你进入分布式锁的世界。

老规矩先上图,为了更清晰的了解获取锁,释放锁的过程,下图简化了一些细节,使整个流程更加通畅。

下面将逐个方法去分析。

InterProcessMutex.acquire()

 

复制代码

 1     @Override
       //获得分布式锁,阻塞
 2     public void acquire() throws Exception {
 3         if (!internalLock(-1, null)) {
 4             throw new IOException("Lost connection while trying to acquire lock: " + basePath);
 5         }
 6     }
 7 
       //获得分布式锁,在指定的时间内阻塞,推荐使用
 8     @Override
 9     public boolean acquire(long time, TimeUnit unit) throws Exception {
10         return internalLock(time, unit);
11     }

复制代码

 

InterProcessMutex.internalLock(long time, TimeUnit unit)

复制代码

 1     private boolean internalLock(long time, TimeUnit unit) throws Exception {
 2 
 3         Thread currentThread = Thread.currentThread();
 4         //获得当前线程的锁对象
 5         LockData lockData = threadData.get(currentThread);
 6         if (lockData != null) {
 7             // re-entering
               //如果锁不为空,当前线程已经获得锁,可重入锁,lockCount++   
 8             lockData.lockCount.incrementAndGet();
 9             return true;
10         }
11 
           //获取锁,返回锁的节点路径
12         String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());
13         if (lockPath != null) {
               //将当前线程的锁对象信息保存起来
14             LockData newLockData = new LockData(currentThread, lockPath);
15             threadData.put(currentThread, newLockData);
16             return true;
17         }
18 
19         return false;
20     }

复制代码

LockInternals.attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes)

复制代码

 1     String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception {
 2         final long startMillis = System.currentTimeMillis();
 3         final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;//等待时间,毫秒
 4         final byte[] localLockNodeBytes = (revocable.get() != null) ? new byte[0] : lockNodeBytes;
 5         int retryCount = 0;
 6 
 7         String ourPath = null;
 8         boolean hasTheLock = false;
 9         boolean isDone = false;
10         while (!isDone) {
11             isDone = true;
12 
13             try {
                   //在当前path下创建临时有序节点
14                 ourPath = driver.createsTheLock(client, path, localLockNodeBytes);
                   //判断是不是序号最小的节点,如果是返回true,否则阻塞等待
15                 hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);
16             } catch (KeeperException.NoNodeException e) {
17                 if (client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper())) {
18                     isDone = false;
19                 } else {
20                     throw e;
21                 }
22             }
23         }
24 
25         if (hasTheLock) {
26             return ourPath;
27         }
28 
29         return null;
30     }

复制代码

StandardLockInternalsDriver.createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes)

复制代码

 1     @Override
 2     public String createsTheLock(CuratorFramework client, String path, byte[] lockNodeBytes) throws Exception {
 3         String ourPath;
           //在zookeeper的指定路径上,创建一个临时序列节点。只是纯粹的创建了一个节点,并不是说线程已经持有了锁。  
 4         if (lockNodeBytes != null) {
 5             ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, lockNodeBytes);
 6         } else {
 7             ourPath = client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
 8         }
 9         return ourPath;
10     }

复制代码

LockInternals.internalLockLoop(long startMillis, Long millisToWait, String ourPath)

复制代码

 1     private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception {
 2         boolean haveTheLock = false;
 3         boolean doDelete = false;
 4         try {
 5             if (revocable.get() != null) {
 6                 client.getData().usingWatcher(revocableWatcher).forPath(ourPath);
 7             }
 8 
 9             while ((client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock) {
            //获得所有子节点
10                 List<String> children = getSortedChildren();
11                 String sequenceNodeName = ourPath.substring(basePath.length() + 1); // +1 to include the slash
12 
13                 PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName, maxLeases);
                   //判断是否是最小节点
14                 if (predicateResults.getsTheLock()) {
15                     haveTheLock = true;
16                 } else {
17                     String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();
18             //同步,是为了实现公平锁
19                     synchronized (this) {
20                         try {
                               //给比自己小的节点设置监听器
21                             client.getData().usingWatcher(watcher).forPath(previousSequencePath);
22                             if (millisToWait != null) {
23                                 millisToWait -= (System.currentTimeMillis() - startMillis);
24                                 startMillis = System.currentTimeMillis();
                                   //等待超时,超时删除临时节点,超时时间是acquire方法传入的参数
25                                 if (millisToWait <= 0) {
26                                     doDelete = true;    // timed out - delete our node
27                                     break;
28                                 }
29                                 //没有超时,继续等待
30                                 wait(millisToWait);
31                             } else {
                                   //如果等待时间==null,一直阻塞等待
32                                 wait();
33                             }
34                         } catch (KeeperException.NoNodeException e) {
35                             // it has been deleted (i.e. lock released). Try to acquire again
36                         }
37                     }
38                 }
39             }
40         } catch (Exception e) {
41             ThreadUtils.checkInterrupted(e);
42             doDelete = true;
43             throw e;
44         } finally {
45             if (doDelete) {
46                 deleteOurPath(ourPath);//如果如果抛出异常或超时,都会删除临时节点
47             }
48         }
49         return haveTheLock;
50     }

复制代码

LockInternals.getSortedChildren()

复制代码

 1     List<String> getSortedChildren() throws Exception {
 2         return getSortedChildren(client, basePath, lockName, driver);
 3     }
 4 
 5     public static List<String> getSortedChildren(CuratorFramework client, String basePath, final String lockName, final LockInternalsSorter sorter) throws Exception {
 6         try {
               //获得basePath下所有子节点,进行排序
 7             List<String> children = client.getChildren().forPath(basePath);
 8             List<String> sortedList = Lists.newArrayList(children);
 9             Collections.sort(sortedList, new Comparator<String>() {
10                 @Override
11                 public int compare(String lhs, String rhs) {
12                     return sorter.fixForSorting(lhs, lockName).compareTo(sorter.fixForSorting(rhs, lockName));
13                 }
14             });
15             return sortedList;
16         } catch (KeeperException.NoNodeException ignore) {
17             return Collections.emptyList();
18         }
19     }

复制代码

StandardLockInternalsDriver.getsTheLock(CuratorFramework c, List<String> child, String nodeName, int max)

复制代码

 1     @Override
 2     public PredicateResults getsTheLock(CuratorFramework client, List<String> children, String sequenceNodeName, int maxLeases) throws Exception {
 3         int ourIndex = children.indexOf(sequenceNodeName);
 4         validateOurIndex(sequenceNodeName, ourIndex);
 5 
 6         boolean getsTheLock = ourIndex < maxLeases;
 7         String pathToWatch = getsTheLock ? null : children.get(ourIndex - maxLeases);
 8 
 9         return new PredicateResults(pathToWatch, getsTheLock);
10     }

复制代码

LockInternals.deleteOurPath(String ourPath)

复制代码

1     private void deleteOurPath(String ourPath) throws Exception {
2         try {
3             client.delete().guaranteed().forPath(ourPath);
4         } catch (KeeperException.NoNodeException e) {
5             // ignore - already deleted (possibly expired session, etc.)
6         }
7     }

复制代码

InterProcessMutex.release()

复制代码

 1     @Override
 2     public void release() throws Exception {
 3         /*
 4             Note on concurrency: a given lockData instance
 5             can be only acted on by a single thread so locking isn't necessary
 6          */
 7 
 8         Thread currentThread = Thread.currentThread();
 9         LockData lockData = threadData.get(currentThread);
           //如果当前线程没有持有锁,不能释放
10         if (lockData == null) {
11             throw new IllegalMonitorStateException("You do not own the lock: " + basePath);
12         }
13 
           //重入锁计数减一,如果还大于0,不能释放。直到所有重入业务完成,计数为0才能释放
14         int newLockCount = lockData.lockCount.decrementAndGet();
15         if (newLockCount > 0) {
16             return;
17         }
18         if (newLockCount < 0) {
19             throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + basePath);
20         }
21         try {
22             internals.releaseLock(lockData.lockPath);
23         } finally {
24             threadData.remove(currentThread);
25         }
26     }

复制代码

LockInternals.release()

1     final void releaseLock(String lockPath) throws Exception {
2         client.removeWatchers();//删除监听
3         revocable.set(null);
4         deleteOurPath(lockPath);//删除Path
5     }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值