飞道的博客

zookeeper——分布式锁的基本原理与基本实现(基于zookeeper自带Java客户端)

207人阅读  评论(0)

实现思路

实现的分布式锁的最常见方式是使用redis分布式锁(redis分布式锁参考我的专栏——分布式锁),基本原理是在各个服务执行到临界区(造作共享资源的代码块)之前,去redis中尝试添加一个带有当前贡献资源标识的redis数据,如果redis中没有该键值,添加成功,代表加锁成功,如果redis中已经存在该键值,添加失败,则加锁失败。

而zookeeper的原理就完全不一样了:

  1. 首先,每个客户端会去某个指定的znode(一般情况,一类分布式锁都创建在某一个node path下)下创建临时有序节点,所以每个客户端创建出来的临时节点都会按照序列分配序号如/locks/lock_000000001、/locks/lock_000000002、/locks/lock_000000003.......
  2. 客户端获取到/lock下的子节点,并进行排序,判断排在最前面的节点是否是自己创建的节点,如果是,那么就获取到锁。
  3. 如果自己创建的节点并不在第一个,则监听前一个节点
  4. 前一个节点的客户端执行完毕,释放锁之后,就会触发监听,通知到下一个节点的客户端
  5. 监听客户端重新执行第2步动作,尝试获取锁

基本实现

本文的demo示例仅作为zookeeper分布式锁的原理分析示例!!!

引入zookeeper自带Java客户端


  
  1. <dependency>
  2. <groupId>org.apache.zookeeper </groupId>
  3. <artifactId>zookeeper </artifactId>
  4. <version>3.7.0 </version>
  5. </dependency>

编写示例


  
  1. package org.leolee.zookeeper.distributedLock;
  2. import org.apache.zookeeper.*;
  3. import org.apache.zookeeper.data.Stat;
  4. import java.io.IOException;
  5. import java.util.Collections;
  6. import java.util.List;
  7. import java.util.concurrent.CountDownLatch;
  8. /**
  9. * @ClassName MyLock
  10. * @Description: 分布式锁
  11. * @Author LeoLee
  12. * @Date 2021/4/14
  13. * @Version V1.0
  14. **/
  15. public class MyLock {
  16. private static final String IP = "127.0.0.1:2181";
  17. CountDownLatch countDownLatch = new CountDownLatch( 1);
  18. ZooKeeper zooKeeper;
  19. private static final String LOCK_ROOT_PATH = "/locks";
  20. private static final String LOCK_NODE_NAME = "lock_";
  21. private String lockPath;
  22. //连接zookeeper
  23. public MyLock() {
  24. try {
  25. zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
  26. @Override
  27. public void process(WatchedEvent watchedEvent) {
  28. if (watchedEvent.getState().equals(Event.KeeperState.SyncConnected)) {
  29. System.out.println( "connect success");
  30. countDownLatch.countDown();
  31. } else if (watchedEvent.getState().equals(Event.KeeperState.Disconnected)) {
  32. System.out.println( "connection break");
  33. } else if (watchedEvent.getState().equals(Event.KeeperState.Expired)) {
  34. System.out.println( "session timeout");
  35. } else if (watchedEvent.getState().equals(Event.KeeperState.AuthFailed)) {
  36. System.out.println( "auth failed");
  37. }
  38. }
  39. });
  40. countDownLatch.await();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. Watcher watcher = new Watcher() {
  48. @Override
  49. public void process(WatchedEvent watchedEvent) {
  50. //监视的前一个节点被删掉后通知
  51. if (watchedEvent.getType().equals(Event.EventType.NodeDeleted)) {
  52. synchronized (watcher) {
  53. watcher.notifyAll();
  54. }
  55. }
  56. }
  57. };
  58. /**
  59. * 功能描述: <br>
  60. * 〈〉获取锁
  61. * @Param: []
  62. * @Return: void
  63. * @Author: LeoLee
  64. * @Date: 2021/4/14 23:00
  65. */
  66. public void acquireLock() throws KeeperException, InterruptedException {
  67. createLock();
  68. tryLock();
  69. }
  70. private void createLock() throws KeeperException, InterruptedException {
  71. //判断锁根节点是否存在
  72. Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, false);
  73. if (stat == null) {
  74. zooKeeper.create(LOCK_ROOT_PATH, new byte[ 0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  75. }
  76. //创建锁节点(临时有效节点)
  77. lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, new byte[ 0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
  78. System.out.println( "lock node create success, lock path:" + lockPath);
  79. }
  80. private void tryLock() throws KeeperException, InterruptedException {
  81. List<String> children = zooKeeper.getChildren(LOCK_ROOT_PATH, false);
  82. //对子节点进行排序
  83. Collections.sort(children);
  84. int index = children.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1));
  85. if (index == 0) {
  86. System.out.println( "try lock success");
  87. return;
  88. } else {
  89. //获取上一个节点
  90. String preNode = children.get(index - 1);
  91. //对上一个节点进行watch
  92. Stat preNodeStat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + preNode, watcher);
  93. if (preNodeStat == null) {
  94. acquireLock();
  95. } else {
  96. synchronized (watcher) {
  97. watcher.wait();
  98. }
  99. }
  100. }
  101. }
  102. /**
  103. * 功能描述: <br>
  104. * 〈〉释放锁
  105. * @Param: []
  106. * @Return: void
  107. * @Author: LeoLee
  108. * @Date: 2021/4/14 23:01
  109. */
  110. public void releaseLock() throws KeeperException, InterruptedException {
  111. //删除临时有序节点
  112. zooKeeper.delete(lockPath, - 1);
  113. System.out.println( "lock release");
  114. zooKeeper.close();
  115. }
  116. }

 


转载:https://blog.csdn.net/qq_25805331/article/details/115705694
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场