<span id="35v3v"><th id="35v3v"></th></span>
<address id="35v3v"></address>

    <address id="35v3v"></address>
      <address id="35v3v"><listing id="35v3v"><meter id="35v3v"></meter></listing></address>
        <listing id="35v3v"><listing id="35v3v"></listing></listing>

        <listing id="35v3v"><listing id="35v3v"><menuitem id="35v3v"></menuitem></listing></listing>

        <noframes id="35v3v"><noframes id="35v3v">
        當前位置: 首頁 / 技術分享 / 正文
        分布式鎖的實現(二)

        2023-01-12

           節點

          4.4. 子節點實現的鎖

          在生產環境中,使用子節點做分布式鎖的實現的場景是最常見的,包括阻塞型的鎖和非阻塞型的鎖。因此,設計子節點實現的鎖的父類,提供公共的處理邏輯。將阻塞型和非阻塞型的實現不同的邏輯分別在子類中實現即可。

          package com.qianfeng.lock.childNodeLock;

          import com.qianfeng.lock.ZkLocker;

          import com.qianfeng.lock.ZkLockerBase;

          import org.apache.zookeeper.CreateMode;

          import org.apache.zookeeper.KeeperException;

          import java.util.Collections;

          import java.util.List;

          /**

          * @author 千鋒大數據教研院 - 章魚哥

          * @company 北京千鋒互聯科技有限公司

          */

          public abstract class ZkChildNodeLockerBase extends ZkLockerBase implements ZkLocker {

          /**

          * 創建的子節點鎖的全路徑

          */

          protected String nodeFullPath;

          public ZkChildNodeLockerBase(String connectString, String lockName) {

          super(connectString, lockName);

          createLockNode();

          }

          public ZkChildNodeLockerBase(String lockName) {

          super();

          this.lockName = lockName;

          createLockNode();

          }

          // 創建鎖節點

          public void createLockNode() {

          // 1. 判斷節點是否存在

          if (!exists(getLockName())) {

          // 3. 創建鎖節點

          createNode(getLockName(), CreateMode.CONTAINER);

          }

          }

          @Override

          public boolean lock() {

          // 1. 在鎖節點下創建子節點

          this.nodeFullPath = createNode(getLockName() + "/child-", CreateMode.EPHEMERAL_SEQUENTIAL);

          // 2. 判斷是否可以成功上鎖

          return canLock();

          }

          @Override

          public boolean unlock() {

          return deleteNode(this.nodeFullPath);

          }

          @Override

          public boolean exists() {

          // 獲取當前鎖節點下的子節點數量,如果大于0,說明有鎖存在

          try {

          Listchildren = getZkCli().getChildren(getLockName(), false);

          return children.size() > 0;

          } catch (KeeperException | InterruptedException ignored) {

          }

          return false;

          }

          protected abstract boolean canLock();

          /**

          * 獲取當前創建的子節點之前的節點(根據序號)

          * @return 之前的節點

          */

          protected String getPreviousNode() {

          // 定義變量,記錄上一個節點名稱

          String previousNodeName = null;

          try {

          // 1. 獲取鎖節點下所有的子節點

          Listchildren = getZkCli().getChildren(getLockName(), false);

          // 2. 對所有的節點進行名字排序

          Collections.sort(children);

          // 3. 獲取當前創建的子節點名稱

          String childNodeName = this.nodeFullPath.substring(getLockName().length() + 1);

          // 4. 遍歷所有的節點,進行名稱的比對

          for (String child : children) {

          if (child.equals(childNodeName)) {

          break;

          }

          previousNodeName = child;

          }

          } catch (KeeperException | InterruptedException e) {

          e.printStackTrace();

          }

          return previousNodeName;

          }

          }

          4.5. 子節點實現的非阻塞型鎖

          package com.qianfeng.lock.childNodeLock;

          /**

          * @author 千鋒大數據教研院 - 章魚哥

          * @company 北京千鋒互聯科技有限公司

          */

          public class ZkChildNodeNoneBlockingLocker extends ZkChildNodeLockerBase {

          public ZkChildNodeNoneBlockingLocker(String connectString, String lockName) {

          super(connectString, lockName);

          }

          public ZkChildNodeNoneBlockingLocker(String lockName) {

          super(lockName);

          }

          @Override

          protected boolean canLock() {

          // 1. 判斷是否有之前的節點

          String previousNodeName = getPreviousNode();

          // 2. 如果不存在之前的節點,說明上鎖成功

          if (previousNodeName == null) {

          return true;

          }

          // 3. 如果存在之前的節點,說明上鎖失敗,刪除自己創建的子節點即可

          deleteNode(this.nodeFullPath);

          return false;

          }

          }

          4.6. 子節點實現的阻塞型鎖

          A程序在進行上鎖的時候,發現已經被其他的程序獲取到鎖了,自己需要等待其他的程序釋放鎖?;镜膶崿F邏輯就是自己監控已經創建好的節點,發現這個節點消失的時候,自己去創建節點。但是為什么沒有用節點作為鎖來實現阻塞型的鎖呢?是因為這里有“羊群效應”。

          假如有100個程序來獲取鎖,結果發現鎖已經被其他的程序注冊了,于是這100個程序都去監聽這個節點。一旦這個節點被刪除,這100個程序都可以獲取到狀態的變更,會同時請求ZooKeeper創建節點。這樣會帶來瞬時的資源占用劇增,嚴重的甚至可能導致服務器宕機。因此,我們在實現阻塞型鎖的時候,使用的是有序的子節點來實現的,每一個程序監控比自己編號小的節點即可。詳情可參考3.2.章節的內容。

          package com.qianfeng.lock.childNodeLock;

          import org.apache.zookeeper.AddWatchMode;

          import org.apache.zookeeper.KeeperException;

          import java.util.concurrent.CountDownLatch;

          /**

          * @author 千鋒大數據教研院 - 章魚哥

          * @company 北京千鋒互聯科技有限公司

          */

          public class ZkChildNodeBlockingLocker extends ZkChildNodeLockerBase {

          // 等待釋放信號

          private CountDownLatch latch = new CountDownLatch(1);

          public ZkChildNodeBlockingLocker(String connectString, String lockName) {

          super(connectString, lockName);

          }

          public ZkChildNodeBlockingLocker(String lockName) {

          super(lockName);

          }

          @Override

          protected boolean canLock() {

          // 獲取自己創建的子節點之前序號的節點

          String previousNode = getPreviousNode();

          // 如果之前節點不存在,說明已經上鎖成功

          if (previousNode == null) {

          return true;

          }

          // 如果有比當前創建的節點序號更小的節點,說明上鎖失敗,自己阻塞,監聽之前的節點即可

          try {

          getZkCli().addWatch(getLockName() + "/" + previousNode, event -> {

          if (event.getType().equals(Event.EventType.NodeDeleted)) {

          // 說明之前節點被刪除掉了

          latch.countDown();

          }

          }, AddWatchMode.PERSISTENT);

          // 等待信號

          latch.await();

          } catch (KeeperException | InterruptedException e) {

          e.printStackTrace();

          }

          // 自己成為了最小的節點,上鎖成功

          return true;

          }

          }

        好程序員公眾號

        • · 剖析行業發展趨勢
        • · 匯聚企業項目源碼

        好程序員開班動態

        More+
        • HTML5大前端 <高端班>

          開班時間:2021-04-12(深圳)

          開班盛況

          開班時間:2021-05-17(北京)

          開班盛況
        • 大數據+人工智能 <高端班>

          開班時間:2021-03-22(杭州)

          開班盛況

          開班時間:2021-04-26(北京)

          開班盛況
        • JavaEE分布式開發 <高端班>

          開班時間:2021-05-10(北京)

          開班盛況

          開班時間:2021-02-22(北京)

          開班盛況
        • Python人工智能+數據分析 <高端班>

          開班時間:2021-07-12(北京)

          預約報名

          開班時間:2020-09-21(上海)

          開班盛況
        • 云計算開發 <高端班>

          開班時間:2021-07-12(北京)

          預約報名

          開班時間:2019-07-22(北京)

          開班盛況
        在線咨詢
        試聽
        入學教程
        立即報名

        Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號

        黑人100部Av解禁片
        <span id="35v3v"><th id="35v3v"></th></span>
        <address id="35v3v"></address>

          <address id="35v3v"></address>
            <address id="35v3v"><listing id="35v3v"><meter id="35v3v"></meter></listing></address>
              <listing id="35v3v"><listing id="35v3v"></listing></listing>

              <listing id="35v3v"><listing id="35v3v"><menuitem id="35v3v"></menuitem></listing></listing>

              <noframes id="35v3v"><noframes id="35v3v">