ZooKeeper完全解析(七) 使用ZooKeeper實現分散式鎖之Java實現
阿新 • • 發佈:2018-12-21
在上一節中,我們講了使用ZooKeeper來實現分散式鎖的原理,連結為 ZooKeeper完全解析(六) 使用ZooKeeper實現分散式鎖之實現原理 ,這一節我們來講一下如何使用Java來實現分散式鎖:
在實現原理中,我們把使用ZooKeeper實現分散式鎖分成了3步,在Java實現中,我們將第1步寫成一個方法,第2、3步寫成一個方法:
第一步:
public void lock(String lockBasePath,final Runnable runnable) { // 先建立lock節點 try { zooKeeper.create(lockBasePath, "".getBytes(), OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } catch (KeeperException.NodeExistsException e) { } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } if (StringUtils.isEmpty(lockBasePath) || runnable == null) { return; } // 建立一個順序的、臨時的節點 try { String childCurrentPath = zooKeeper.create(lockBasePath + LockConsts.LOCK_CHILD_PATH, "".getBytes(), OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); String[] childPathArray = childCurrentPath.split("[/]"); String childRelativePath = childPathArray[childPathArray.length - 1]; // 開始lock doLock(lockBasePath, childRelativePath, runnable); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }
其中 ,傳入的引數中lockBasePath為鎖的基礎路徑,而裡面子節點的路徑由我們來定義即可,Runnable為當拿到分散式鎖之後,執行的程式碼塊。
首先,我們建立了一個lockBasePath的基礎路徑,然後開始建立了順序的子節點。然後執行第2、3步的方法
第二步:
private void doLock(String lockBasePath,final String childRelativePath, final Runnable runnable) throws KeeperException, InterruptedException { String childCurrentPath = lockBasePath + "/" + childRelativePath; // 遍歷子節點, List<String> masterChildRelativePathList = zooKeeper.getChildren(lockBasePath, false); // 將子節點置為一個有序的子節點,從小到大 masterChildRelativePathList.sort(new ZooChildNodeComparator()); logger.info(childRelativePath + " path " + JSON.toJSONString(masterChildRelativePathList)); // 有兩種情況,一種是第一個節點,一種不是 if (childRelativePath.equals(masterChildRelativePathList.get(0))) { logger.info(childRelativePath + " 搶到了分散式鎖,開始執行"); // 說明搶到了分散式鎖,開始做分散式任務,完成之後,將節點刪除 runnable.run(); logger.info(childRelativePath + " 搶到了分散式鎖,執行完成"); // 刪除節點 zooKeeper.delete(childCurrentPath, -1); logger.info(childRelativePath + " 執行完成後刪除了節點\n\n\n"); } else { // 監聽上一個節點,如果上一個節點刪除,再遍歷子節點 int currentPathIndex = masterChildRelativePathList.indexOf(childRelativePath); // 監聽上一個節點 String childPreRelativePath = masterChildRelativePathList.get(currentPathIndex - 1); String childPreCurrentPath = lockBasePath + "/" + childPreRelativePath; logger.info(childRelativePath + " 監聽 " + childPreRelativePath); zooKeeper.getData(childPreCurrentPath, event -> { if (Watcher.Event.EventType.NodeDeleted != event.getType()) { logger.info("節點非刪除 " + event.getType().getIntValue()); return; } logger.info(childRelativePath + " 上一個節點被刪除,開始繼續lock"); // 重複 doLock try { doLock(lockBasePath, childRelativePath, runnable); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }, null); } }
可以看到,在這步中,我們首先遍歷子節點,如果發現自己是第一個,那麼開始執行程式碼塊,如果沒有,那麼監聽上一個節點,如果上一個節點被刪除,重新走這個方法。
使用ZooKeeper實現分散式鎖的Java實現程式碼在 實現程式碼 ,歡迎大家提修改意見和star