Zookeeper分布式锁实现

https://blog.csdn.net/evankaka/article/details/70570941


  摘要:本文要使用Zookeeper来实现一个分布式锁,是一个悲观锁。

    本文源码请在这里下载:https://github.com/appleappleapple/DistributeLearning

一、锁设计

  获取锁实现思路:
1. 首先创建一个作为锁目录(znode),通常用它来描述锁定的实体,称为:/lock_node
2. 希望获得锁的客户端在锁目录下创建znode,作为锁/lock_node的子节点,并且节点类型为有序临时节点(EPHEMERAL_SEQUENTIAL);
例如:有两个客户端创建znode,分别为/lock_node/lock-1和/lock_node/lock-2
3. 当前客户端调用getChildren(/lock_node)得到锁目录所有子节点,不设置watch,接着获取小于自己(步骤2创建)的兄弟节点
4. 步骤3中获取小于自己的节点不存在 && 最小节点与步骤2中创建的相同,说明当前客户端顺序号最小,获得锁,结束。
5. 客户端监视(watch)相对自己次小的有序临时节点状态
6. 如果监视的次小节点状态发生变化,则跳转到步骤3,继续后续操作,直到退出锁竞争。     

分布锁笔者这里就不做介绍了,来看看整个代码设计的流程图如下


二、代码

接下来我们就开始编程了~

1、DistributedLock接口定义

[java] view plain copy
  1. package com.github.distribute.lock;  
  2.   
  3. import java.util.concurrent.TimeUnit;  
  4.   
  5. public interface DistributedLock {  
  6.   
  7.     /** 
  8.      * 尝试获取锁,不进行等待。得到返回true, 
  9.      *  
  10.      * @return 
  11.      * @throws Exception 
  12.      */  
  13.     public boolean tryLock() throws Exception;  
  14.   
  15.     /** 
  16.      * 阻塞等待获取锁 
  17.      *  
  18.      * @throws Exception 
  19.      */  
  20.     public void lock() throws Exception;  
  21.   
  22.     /** 
  23.      * 在规定时间内等待获取锁 
  24.      *  
  25.      * @param time 
  26.      * @param unit 
  27.      * @return 
  28.      * @throws Exception 
  29.      */  
  30.     public boolean lock(long time, TimeUnit unit) throws Exception;  
  31.   
  32.     /** 
  33.      * 释放锁 
  34.      *  
  35.      * @throws Exception 
  36.      */  
  37.     public void unLock() throws Exception;  
  38.   
  39. }  

2、部分实现BaseDistributedLock

[java] view plain copy
  1. package com.github.distribute.zookeeper;  
  2.   
  3. import java.util.Collections;  
  4. import java.util.Comparator;  
  5. import java.util.List;  
  6. import java.util.concurrent.CountDownLatch;  
  7. import java.util.concurrent.TimeUnit;  
  8.   
  9. import org.apache.zookeeper.CreateMode;  
  10. import org.apache.zookeeper.WatchedEvent;  
  11. import org.apache.zookeeper.Watcher;  
  12. import org.apache.zookeeper.Watcher.Event.EventType;  
  13. import org.apache.zookeeper.ZooDefs;  
  14. import org.apache.zookeeper.ZooKeeper;  
  15. import org.apache.zookeeper.data.Stat;  
  16. import org.slf4j.Logger;  
  17. import org.slf4j.LoggerFactory;  
  18.   
  19. import com.github.distribute.lock.DistributedLock;  
  20.   
  21. public abstract class BaseDistributedLock implements DistributedLock {  
  22.   
  23.     private static Logger logger = LoggerFactory.getLogger(BaseDistributedLock.class);  
  24.   
  25.     private ZooKeeper zooKeeper;  
  26.     private String rootPath;// 根路径名  
  27.     private String lockNamePre;// 锁前缀  
  28.     private String currentLockPath;// 用于保存某个客户端在locker下面创建成功的顺序节点,用于后续相关操作使用(如判断)  
  29.     private static int MAX_RETRY_COUNT = 10;// 最大重试次数  
  30.       
  31.   
  32.       
  33.     /** 
  34.      * 初始化根目录 
  35.      */  
  36.     private void init() {  
  37.         try {  
  38.             Stat stat = zooKeeper.exists(rootPath, false);// 判断一下根目录是否存在  
  39.             if (stat == null) {  
  40.                 zooKeeper.create(rootPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  41.             }  
  42.         } catch (Exception e) {  
  43.             logger.error("create rootPath error", e);  
  44.         }  
  45.     }  
  46.   
  47.     /** 
  48.      * 取得锁的排序号 
  49.      *  
  50.      * @param str 
  51.      * @param lockName 
  52.      * @return 
  53.      */  
  54.     private String getLockNodeNumber(String str, String lockName) {  
  55.         int index = str.lastIndexOf(lockName);  
  56.         if (index >= 0) {  
  57.             index += lockName.length();  
  58.             return index <= str.length() ? str.substring(index) : "";  
  59.         }  
  60.         return str;  
  61.     }  
  62.   
  63.     /** 
  64.      * 取得锁的排序列表 
  65.      *  
  66.      * @return 
  67.      * @throws Exception 
  68.      */  
  69.     private List<String> getSortedChildren() throws Exception {  
  70.         List<String> children = zooKeeper.getChildren(rootPath, false);  
  71.         if (children != null && !children.isEmpty()) {  
  72.             Collections.sort(children, new Comparator<String>() {  
  73.                 public int compare(String lhs, String rhs) {  
  74.                     return getLockNodeNumber(lhs, lockNamePre).compareTo(getLockNodeNumber(rhs, lockNamePre));  
  75.                 }  
  76.             });  
  77.         }  
  78.         logger.info("sort childRen:{}", children);  
  79.         return children;  
  80.     }  
  81.   
  82.     /** 
  83.      * 删除锁节点 
  84.      */  
  85.     private void deleteLockNode() {  
  86.         try {  
  87.             zooKeeper.delete(currentLockPath, -1);  
  88.         } catch (Exception e) {  
  89.             logger.error("unLock error", e);  
  90.   
  91.         }  
  92.     }  
  93.   
  94.     /** 
  95.      * 该方法用于判断自己是否获取到了锁,即自己创建的顺序节点在locker的所有子节点中是否最小.如果没有获取到锁,则等待其它客户端锁的释放, 
  96.      * 并且稍后重试直到获取到锁或者超时 
  97.      *  
  98.      * @param startMillis 
  99.      * @param millisToWait 
  100.      * @param ourPath 
  101.      * @return 
  102.      * @throws Exception 
  103.      */  
  104.     private boolean waitToLock(long startMillis, Long millisToWait) throws Exception {  
  105.   
  106.         boolean haveTheLock = false;  
  107.         boolean doDelete = false;  
  108.   
  109.         try {  
  110.             while (!haveTheLock) {  
  111.                 logger.info("get Lock Begin");  
  112.                 // 该方法实现获取locker节点下的所有顺序节点,并且从小到大排序,  
  113.                 List<String> children = getSortedChildren();  
  114.                 String sequenceNodeName = currentLockPath.substring(rootPath.length() + 1);  
  115.   
  116.                 // 计算刚才客户端创建的顺序节点在locker的所有子节点中排序位置,如果是排序为0,则表示获取到了锁  
  117.                 int ourIndex = children.indexOf(sequenceNodeName);  
  118.   
  119.                 /* 
  120.                  * 如果在getSortedChildren中没有找到之前创建的[临时]顺序节点,这表示可能由于网络闪断而导致 
  121.                  * Zookeeper认为连接断开而删除了我们创建的节点,此时需要抛出异常,让上一级去处理 
  122.                  * 上一级的做法是捕获该异常,并且执行重试指定的次数 见后面的 attemptLock方法 
  123.                  */  
  124.                 if (ourIndex < 0) {  
  125.                     logger.error("not find node:{}", sequenceNodeName);  
  126.                     throw new Exception("节点没有找到: " + sequenceNodeName);  
  127.                 }  
  128.   
  129.                 // 如果当前客户端创建的节点在locker子节点列表中位置大于0,表示其它客户端已经获取了锁  
  130.                 // 此时当前客户端需要等待其它客户端释放锁,  
  131.                 boolean isGetTheLock = ourIndex == 0;  
  132.   
  133.                 // 如何判断其它客户端是否已经释放了锁?从子节点列表中获取到比自己次小的哪个节点,并对其建立监听  
  134.                 String pathToWatch = isGetTheLock ? null : children.get(ourIndex - 1);  
  135.   
  136.                 if (isGetTheLock) {  
  137.                     logger.info("get the lock,currentLockPath:{}", currentLockPath);  
  138.                     haveTheLock = true;  
  139.                 } else {  
  140.                     // 如果次小的节点被删除了,则表示当前客户端的节点应该是最小的了,所以使用CountDownLatch来实现等待  
  141.                     String previousSequencePath = rootPath.concat("/").concat(pathToWatch);  
  142.                     final CountDownLatch latch = new CountDownLatch(1);  
  143.                     final Watcher previousListener = new Watcher() {  
  144.                         public void process(WatchedEvent event) {  
  145.                             if (event.getType() == EventType.NodeDeleted) {  
  146.                                 latch.countDown();  
  147.                             }  
  148.                         }  
  149.                     };  
  150.   
  151.                     // 如果节点不存在会出现异常  
  152.                     zooKeeper.exists(previousSequencePath, previousListener);  
  153.   
  154.                     // 如果有超时时间,刚到超时时间就返回  
  155.                     if (millisToWait != null) {  
  156.                         millisToWait -= (System.currentTimeMillis() - startMillis);  
  157.                         startMillis = System.currentTimeMillis();  
  158.                         if (millisToWait <= 0) {  
  159.                             doDelete = true// timed out - delete our node  
  160.                             break;  
  161.                         }  
  162.   
  163.                         latch.await(millisToWait, TimeUnit.MICROSECONDS);  
  164.                     } else {  
  165.                         latch.await();  
  166.                     }  
  167.                 }  
  168.             }  
  169.         } catch (Exception e) {  
  170.             // 发生异常需要删除节点  
  171.             logger.error("waitToLock exception", e);  
  172.             doDelete = true;  
  173.             throw e;  
  174.         } finally {  
  175.             // 如果需要删除节点  
  176.             if (doDelete) {  
  177.                 deleteLockNode();  
  178.             }  
  179.         }  
  180.         logger.info("get Lock end,haveTheLock=" + haveTheLock);  
  181.         return haveTheLock;  
  182.     }  
  183.   
  184.     /** 
  185.      * createLockNode用于在locker(basePath持久节点)下创建客户端要获取锁的[临时]顺序节点 
  186.      *  
  187.      * @param path 
  188.      * @return 
  189.      * @throws Exception 
  190.      */  
  191.     private String createLockNode(String path) throws Exception {  
  192.         Stat stat = zooKeeper.exists(rootPath, false);  
  193.         // 判断一下根目录是否存在  
  194.         if (stat == null) {  
  195.             zooKeeper.create(rootPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  196.         }  
  197.         return zooKeeper.create(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);  
  198.     }  
  199.   
  200.     /** 
  201.      * 尝试获取锁,如果不加超时时间,阻塞等待。否则,就是加了超时的阻塞等待 
  202.      *  
  203.      * @param time 
  204.      * @param unit 
  205.      * @return 
  206.      * @throws Exception 
  207.      */  
  208.     protected Boolean attemptLock(long time, TimeUnit unit) throws Exception {  
  209.         final long startMillis = System.currentTimeMillis();  
  210.         final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;  
  211.   
  212.         boolean hasTheLock = false;  
  213.         boolean isDone = false;  
  214.         int retryCount = 0;  
  215.   
  216.         // 网络闪断需要重试一试,最大重试次数MAX_RETRY_COUNT  
  217.         while (!isDone) {  
  218.             isDone = true;  
  219.             try {  
  220.                 currentLockPath = createLockNode(rootPath.concat("/").concat(lockNamePre));  
  221.                 hasTheLock = waitToLock(startMillis, millisToWait);  
  222.   
  223.             } catch (Exception e) {  
  224.                 if (retryCount++ < MAX_RETRY_COUNT) {  
  225.                     isDone = false;  
  226.                 } else {  
  227.                     throw e;  
  228.                 }  
  229.             }  
  230.         }  
  231.   
  232.         return hasTheLock;  
  233.     }  
  234. }  
waitToLock是最主要的代码

3、完整实现

[java] view plain copy
  1. package com.github.distribute.zookeeper;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Collections;  
  5. import java.util.Comparator;  
  6. import java.util.List;  
  7. import java.util.concurrent.CountDownLatch;  
  8. import java.util.concurrent.TimeUnit;  
  9.   
  10. import org.apache.zookeeper.CreateMode;  
  11. import org.apache.zookeeper.WatchedEvent;  
  12. import org.apache.zookeeper.Watcher;  
  13. import org.apache.zookeeper.Watcher.Event.EventType;  
  14. import org.apache.zookeeper.ZooDefs;  
  15. import org.apache.zookeeper.ZooKeeper;  
  16. import org.apache.zookeeper.data.Stat;  
  17. import org.slf4j.Logger;  
  18. import org.slf4j.LoggerFactory;  
  19.   
  20. import com.github.distribute.lock.DistributedLock;  
  21.   
  22. public class ZookeeperDistributeLock implements DistributedLock {  
  23.   
  24.     private static Logger logger = LoggerFactory.getLogger(ZookeeperDistributeLock.class);  
  25.   
  26.     public static void main(String[] args) throws IOException {  
  27.         ZooKeeper zooKeeper = new ZooKeeper("127.0.0.1:2181"60000null);  
  28.         ZookeeperDistributeLock myLock = new ZookeeperDistributeLock(zooKeeper, "/test""lock-");  
  29.         while (true) {  
  30.             try {  
  31.                 myLock.lock();  
  32.                 Thread.sleep(5000);  
  33.   
  34.             } catch (Exception e) {  
  35.   
  36.             } finally {  
  37.                 myLock.unLock();  
  38.             }  
  39.         }  
  40.   
  41.     }  
  42.   
  43.     private ZooKeeper zooKeeper;  
  44.     private String rootPath;// 根路径名  
  45.     private String lockNamePre;// 锁前缀  
  46.     private String currentLockPath;// 用于保存某个客户端在locker下面创建成功的顺序节点,用于后续相关操作使用(如判断)  
  47.     private static int MAX_RETRY_COUNT = 10;// 最大重试次数  
  48.   
  49.     public ZookeeperDistributeLock(ZooKeeper zookeeper, String rootPath, String lockNamePre) {  
  50.         logger.info("rootPath:{},lockNamePre:{}", rootPath, lockNamePre);  
  51.         this.zooKeeper = zookeeper;  
  52.         this.rootPath = rootPath;  
  53.         this.lockNamePre = lockNamePre;  
  54.         init();  
  55.     }  
  56.   
  57.     /** 
  58.      * 初始化根目录 
  59.      */  
  60.     private void init() {  
  61.         try {  
  62.             Stat stat = zooKeeper.exists(rootPath, false);// 判断一下根目录是否存在  
  63.             if (stat == null) {  
  64.                 zooKeeper.create(rootPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  65.             }  
  66.         } catch (Exception e) {  
  67.             logger.error("create rootPath error", e);  
  68.         }  
  69.     }  
  70.   
  71.     /** 
  72.      * 取得锁的排序号 
  73.      *  
  74.      * @param str 
  75.      * @param lockName 
  76.      * @return 
  77.      */  
  78.     private String getLockNodeNumber(String str, String lockName) {  
  79.         int index = str.lastIndexOf(lockName);  
  80.         if (index >= 0) {  
  81.             index += lockName.length();  
  82.             return index <= str.length() ? str.substring(index) : "";  
  83.         }  
  84.         return str;  
  85.     }  
  86.   
  87.     /** 
  88.      * 取得锁的排序列表 
  89.      *  
  90.      * @return 
  91.      * @throws Exception 
  92.      */  
  93.     private List<String> getSortedChildren() throws Exception {  
  94.         List<String> children = zooKeeper.getChildren(rootPath, false);  
  95.         if (children != null && !children.isEmpty()) {  
  96.             Collections.sort(children, new Comparator<String>() {  
  97.                 public int compare(String lhs, String rhs) {  
  98.                     return getLockNodeNumber(lhs, lockNamePre).compareTo(getLockNodeNumber(rhs, lockNamePre));  
  99.                 }  
  100.             });  
  101.         }  
  102.         logger.info("sort childRen:{}", children);  
  103.         return children;  
  104.     }  
  105.   
  106.     /** 
  107.      * 该方法用于判断自己是否获取到了锁,即自己创建的顺序节点在locker的所有子节点中是否最小.如果没有获取到锁,则等待其它客户端锁的释放, 
  108.      * 并且稍后重试直到获取到锁或者超时 
  109.      *  
  110.      * @param startMillis 
  111.      * @param millisToWait 
  112.      * @param ourPath 
  113.      * @return 
  114.      * @throws Exception 
  115.      */  
  116.     private boolean waitToLock(long startMillis, Long millisToWait) throws Exception {  
  117.   
  118.         boolean haveTheLock = false;  
  119.         boolean doDelete = false;  
  120.   
  121.         try {  
  122.             while (!haveTheLock) {  
  123.                 logger.info("get Lock Begin");  
  124.                 // 该方法实现获取locker节点下的所有顺序节点,并且从小到大排序,  
  125.                 List<String> children = getSortedChildren();  
  126.                 String sequenceNodeName = currentLockPath.substring(rootPath.length() + 1);  
  127.   
  128.                 // 计算刚才客户端创建的顺序节点在locker的所有子节点中排序位置,如果是排序为0,则表示获取到了锁  
  129.                 int ourIndex = children.indexOf(sequenceNodeName);  
  130.   
  131.                 /* 
  132.                  * 如果在getSortedChildren中没有找到之前创建的[临时]顺序节点,这表示可能由于网络闪断而导致 
  133.                  * Zookeeper认为连接断开而删除了我们创建的节点,此时需要抛出异常,让上一级去处理 
  134.                  * 上一级的做法是捕获该异常,并且执行重试指定的次数 见后面的 attemptLock方法 
  135.                  */  
  136.                 if (ourIndex < 0) {  
  137.                     logger.error("not find node:{}", sequenceNodeName);  
  138.                     throw new Exception("节点没有找到: " + sequenceNodeName);  
  139.                 }  
  140.   
  141.                 // 如果当前客户端创建的节点在locker子节点列表中位置大于0,表示其它客户端已经获取了锁  
  142.                 // 此时当前客户端需要等待其它客户端释放锁,  
  143.                 boolean isGetTheLock = ourIndex == 0;  
  144.   
  145.                 // 如何判断其它客户端是否已经释放了锁?从子节点列表中获取到比自己次小的哪个节点,并对其建立监听  
  146.                 String pathToWatch = isGetTheLock ? null : children.get(ourIndex - 1);  
  147.   
  148.                 if (isGetTheLock) {  
  149.                     logger.info("get the lock,currentLockPath:{}", currentLockPath);  
  150.                     haveTheLock = true;  
  151.                 } else {  
  152.                     // 如果次小的节点被删除了,则表示当前客户端的节点应该是最小的了,所以使用CountDownLatch来实现等待  
  153.                     String previousSequencePath = rootPath.concat("/").concat(pathToWatch);  
  154.                     final CountDownLatch latch = new CountDownLatch(1);  
  155.                     final Watcher previousListener = new Watcher() {  
  156.                         public void process(WatchedEvent event) {  
  157.                             if (event.getType() == EventType.NodeDeleted) {  
  158.                                 latch.countDown();  
  159.                             }  
  160.                         }  
  161.                     };  
  162.   
  163.                     // 如果节点不存在会出现异常  
  164.                     zooKeeper.exists(previousSequencePath, previousListener);  
  165.   
  166.                     // 如果有超时时间,刚到超时时间就返回  
  167.                     if (millisToWait != null) {  
  168.                         millisToWait -= (System.currentTimeMillis() - startMillis);  
  169.                         startMillis = System.currentTimeMillis();  
  170.                         if (millisToWait <= 0) {  
  171.                             doDelete = true// timed out - delete our node  
  172.                             break;  
  173.                         }  
  174.   
  175.                         latch.await(millisToWait, TimeUnit.MICROSECONDS);  
  176.                     } else {  
  177.                         latch.await();  
  178.                     }  
  179.                 }  
  180.             }  
  181.         } catch (Exception e) {  
  182.             // 发生异常需要删除节点  
  183.             logger.error("waitToLock exception", e);  
  184.             doDelete = true;  
  185.             throw e;  
  186.         } finally {  
  187.             // 如果需要删除节点  
  188.             if (doDelete) {  
  189.                 unLock();  
  190.             }  
  191.         }  
  192.         logger.info("get Lock end,haveTheLock=" + haveTheLock);  
  193.         return haveTheLock;  
  194.     }  
  195.   
  196.     /** 
  197.      * createLockNode用于在locker(basePath持久节点)下创建客户端要获取锁的[临时]顺序节点 
  198.      *  
  199.      * @param path 
  200.      * @return 
  201.      * @throws Exception 
  202.      */  
  203.     private String createLockNode(String path) throws Exception {  
  204.         Stat stat = zooKeeper.exists(rootPath, false);  
  205.         // 判断一下根目录是否存在  
  206.         if (stat == null) {  
  207.             zooKeeper.create(rootPath, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  208.         }  
  209.         return zooKeeper.create(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);  
  210.     }  
  211.   
  212.     /** 
  213.      * 尝试获取锁,如果不加超时时间,阻塞等待。否则,就是加了超时的阻塞等待 
  214.      *  
  215.      * @param time 
  216.      * @param unit 
  217.      * @return 
  218.      * @throws Exception 
  219.      */  
  220.     private Boolean attemptLock(long time, TimeUnit unit) throws Exception {  
  221.         final long startMillis = System.currentTimeMillis();  
  222.         final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;  
  223.   
  224.         boolean hasTheLock = false;  
  225.         boolean isDone = false;  
  226.         int retryCount = 0;  
  227.   
  228.         // 网络闪断需要重试一试,最大重试次数MAX_RETRY_COUNT  
  229.         while (!isDone) {  
  230.             isDone = true;  
  231.             try {  
  232.                 currentLockPath = createLockNode(rootPath.concat("/").concat(lockNamePre));  
  233.                 hasTheLock = waitToLock(startMillis, millisToWait);  
  234.   
  235.             } catch (Exception e) {  
  236.                 if (retryCount++ < MAX_RETRY_COUNT) {  
  237.                     isDone = false;  
  238.                 } else {  
  239.                     throw e;  
  240.                 }  
  241.             }  
  242.         }  
  243.   
  244.         return hasTheLock;  
  245.     }  
  246.   
  247.     public boolean tryLock() throws Exception {  
  248.         logger.info("tryLock Lock Begin");  
  249.         // 该方法实现获取locker节点下的所有顺序节点,并且从小到大排序,  
  250.         List<String> children = getSortedChildren();  
  251.         String sequenceNodeName = currentLockPath.substring(rootPath.length() + 1);  
  252.   
  253.         // 计算刚才客户端创建的顺序节点在locker的所有子节点中排序位置,如果是排序为0,则表示获取到了锁  
  254.         int ourIndex = children.indexOf(sequenceNodeName);  
  255.   
  256.         if (ourIndex < 0) {  
  257.             logger.error("not find node:{}", sequenceNodeName);  
  258.             throw new Exception("节点没有找到: " + sequenceNodeName);  
  259.         }  
  260.   
  261.         // 如果当前客户端创建的节点在locker子节点列表中位置大于0,表示其它客户端已经获取了锁  
  262.         return ourIndex == 0;  
  263.     }  
  264.   
  265.     public void lock() throws Exception {  
  266.         // -1,null表示阻塞等待,不设置超时时间  
  267.         attemptLock(-1null);  
  268.   
  269.     }  
  270.   
  271.     public boolean lock(long time, TimeUnit unit) throws Exception {  
  272.         if (time <= 0) {  
  273.             throw new Exception("Lock wait for time must greater than 0");  
  274.         }  
  275.   
  276.         if (unit == null) {  
  277.             throw new Exception("TimeUnit can not be null");  
  278.         }  
  279.   
  280.         return attemptLock(time, unit);  
  281.     }  
  282.   
  283.     public void unLock() {  
  284.         try {  
  285.             zooKeeper.delete(currentLockPath, -1);  
  286.         } catch (Exception e) {  
  287.             logger.error("unLock error", e);  
  288.   
  289.         }  
  290.   
  291.     }  
  292.   
  293. }  


三、对比

在文章Redis分布式锁----悲观锁实现,以秒杀系统为例,我们用redis也实现了分布式锁。zk的方案最大的优势在于避免结点挂掉后导致的死锁;redis的方案最大的优势在于性能超强;在实际生产过程中,结合自身情况来决定最适合的分布式锁。


阅读更多
个人分类:
上一篇Redis分布式锁----乐观锁的实现,以秒杀系统为例
下一篇Redis分布式锁----悲观锁实现,以秒杀系统为例
想对作者说点什么? 我来说一句

springboot zookeeper 分布式锁

2017年05月26日 98KB 下载

Zookeeper实现分布式锁

2018年04月02日 15KB 下载

zk使用curator实现分布式锁

2017年09月20日 2KB 下载

zookeeper 分布式锁

2017年05月10日 5KB 下载

基于zookeeper分布式锁实现demo

2017年12月27日 298KB 下载

zookeeper分布式锁

2017年08月11日 4KB 下载

hadoop代码实现

2017年12月07日 3.06MB 下载

zookeeper 例子

2016年09月11日 42KB 下载

Zookeeper_安装和配置

2016年07月10日 29KB 下载

没有更多推荐了,返回首页

关闭
关闭