ZooKeeper客户端 Curator(三)

简介

  • Curator作为客户端实现了 ZooKeeper的核心接口封装. 大幅度降低了 ZooKeeper的使用复杂度
  • http://curator.apache.org

Curator锁接口源码分析

实现可重入互斥锁, 有两种方法

  1. InterProcessMutex - boolean acquire(long time, TimeUnit unit), 可设置过期时间, 当业务处理或系统故障设定的时间内未执行解锁命令时, 将自动释放锁
  2. 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);
                    }

                }
            }
        }
    }

在这里插入图片描述

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

猜你喜欢

转载自blog.csdn.net/qcl108/article/details/107872120