zookeeper分布式锁的设计思路与实现

分布式锁有多种实现方式,比如通过数据库,redis都可以实现,作为分布式协同工具zookeeper也有着标准的实现方式.
设计思路:

  1. 每个客户端往/Locks下创建临时有序节点/Locks/Lock_,创建成功之后/Locks下面会有每个客户端对应的节点,如/Locks/Lock_0000000001
  2. 客户端取得/Locks下子节点,并进行排序,判断最前面的是否为自己,如果自己的锁节点在第一位,代表获取锁成功.
  3. 如果自己的锁节点不在第一位,则监听自己前一位的锁节点,例如自己锁节点Lock_000000002,那么监听Lock_000000001
  4. 当前一位锁节点(Lock_000000001)对应的科技迪阿敏执行完毕,释放了锁,将会触发监听客户端(Lock_000000002)的逻辑
  5. 监听客户端重新执行第二步逻辑,判断自己是否获得了锁

zookeeper的分布式唯一id以及分布式配置中心的案例github链接 欢迎star

代码如下

package com.sofency.top;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * @author sofency
 * @date 2020/9/20 19:02
 * @package IntelliJ IDEA
 * @description 分布式锁
 */
public class DistributedLock {
    private static final String HOST = "localhost:2181";
    private static final Integer SESSION_TIME_OUT = 5000;
    //计数器对象
    private CountDownLatch countDownLatch = new CountDownLatch(1);

    private ZooKeeper zooKeeper;
    private static final String LOCK_ROOT_PATH = "/Locks";
    private static final String LOCK_NODE_NAME = "Lock_";

    //初始化
    public DistributedLock(){
        try{
            zooKeeper = new ZooKeeper(HOST, SESSION_TIME_OUT, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    if(watchedEvent.getType()==Event.EventType.None){
                        if(watchedEvent.getState()== Event.KeeperState.SyncConnected){
                            System.out.println("创建连接成功");
                            countDownLatch.countDown();
                        }
                    }
                }
            });
            countDownLatch.await();//等待
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    //获取锁
    public void acquireLock() throws KeeperException, InterruptedException {
        createLock();//创建锁
        //尝试获取锁
        attemptLock();
    }

    //创建锁节点
    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);
        }
        //创建临时有序的节点
        String localPath = zooKeeper.create(LOCK_ROOT_PATH + "/" + LOCK_NODE_NAME, new byte[0],
                ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL//临时有序节点
        );
        System.out.println("临时有序节点创建完毕"+localPath);
    }

    Watcher watcher = new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            if(watchedEvent.getType()== Event.EventType.NodeDeleted){//删除掉
                synchronized (this){
                    notifyAll();//唤醒占有当前对象的锁
                }
            }
        }
    };
    
    //尝试获取锁
    private void attemptLock() throws KeeperException, InterruptedException {
        //获取Locks下的所有子节点
        List<String> list  = zooKeeper.getChildren(LOCK_ROOT_PATH,false);
        //对子节点进行排序
        Collections.sort(list);
        int index = list.indexOf(LOCK_NODE_NAME);
        if(index == 0){
            System.out.println("获取锁成功");
            return;
        }else{
            String path = list.get(index-1);//上一个节点的索引位置
            Stat exists = zooKeeper.exists(LOCK_ROOT_PATH + "/" + path, watcher);
            //尝试获取锁
            if (exists != null) {
                synchronized (watcher) {
                    watcher.wait();//等待
                }
            }
            attemptLock();//尝试获取锁
        }

    }

    public static void main(String[] args) throws KeeperException, InterruptedException {
        DistributedLock distributedLock = new DistributedLock();
        distributedLock.createLock();
        distributedLock.close();
    }

    //释放锁
    public void close() throws InterruptedException {
        zooKeeper.close();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值