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

实现思路

实现的分布式锁的最常见方式是使用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客户端


    org.apache.zookeeper
    zookeeper
    3.7.0

编写示例

package org.leolee.zookeeper.distributedLock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName MyLock
 * @Description: 分布式锁
 * @Author LeoLee
 * @Date 2021/4/14
 * @Version V1.0
 **/
public class MyLock {

    private static final String IP = "127.0.0.1:2181";

    CountDownLatch countDownLatch = new CountDownLatch(1);

    ZooKeeper zooKeeper;

    private static final String LOCK_ROOT_PATH = "/locks";

    private static final String LOCK_NODE_NAME = "lock_";

    private String lockPath;

    //连接zookeeper
    public MyLock() {
        try {
            zooKeeper = new ZooKeeper(IP, 5000, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if (watchedEvent.getState().equals(Event.KeeperState.SyncConnected)) {
                        System.out.println("connect success");
                        countDownLatch.countDown();
                    } else if (watchedEvent.getState().equals(Event.KeeperState.Disconnected)) {
                        System.out.println("connection break");
                    } else if (watchedEvent.getState().equals(Event.KeeperState.Expired)) {
                        System.out.println("session timeout");
                    } else if (watchedEvent.getState().equals(Event.KeeperState.AuthFailed)) {
                        System.out.println("auth failed");
                    }
                }
            });
            countDownLatch.await();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            //监视的前一个节点被删掉后通知
            if (watchedEvent.getType().equals(Event.EventType.NodeDeleted)) {
                synchronized (watcher) {
                    watcher.notifyAll();
                }
            }
        }
    };

    /**
     * 功能描述: 
* 〈〉获取锁 * @Param: [] * @Return: void * @Author: LeoLee * @Date: 2021/4/14 23:00 */ public void acquireLock() throws KeeperException, InterruptedException { createLock(); tryLock(); } private void createLock() throws KeeperException, InterruptedException { //判断锁根节点是否存在 Stat stat = zooKeeper.exists(LOCK_ROOT_PATH, false); if (stat == null) { zooKeeper.create(LOCK_ROOT_PATH, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } //创建锁节点(临时有效节点) lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("lock node create success, lock path:" + lockPath); } private void tryLock() throws KeeperException, InterruptedException { List children = zooKeeper.getChildren(LOCK_ROOT_PATH, false); //对子节点进行排序 Collections.sort(children); int index = children.indexOf(lockPath.substring(LOCK_ROOT_PATH.length() + 1)); if (index == 0) { System.out.println("try lock success"); return; } else { //获取上一个节点 String preNode = children.get(index - 1); //对上一个节点进行watch Stat preNodeStat = zooKeeper.exists(LOCK_ROOT_PATH + "/" + preNode, watcher); if (preNodeStat == null) { acquireLock(); } else { synchronized (watcher) { watcher.wait(); } } } } /** * 功能描述:
* 〈〉释放锁 * @Param: [] * @Return: void * @Author: LeoLee * @Date: 2021/4/14 23:01 */ public void releaseLock() throws KeeperException, InterruptedException { //删除临时有序节点 zooKeeper.delete(lockPath, -1); System.out.println("lock release"); zooKeeper.close(); } }

 

你可能感兴趣的:(zookeeper,#,分布式锁,zookeeper,分布式锁)