zookeeper(reactive模型)分布式锁的简单实现

  1. 环境准备
    1.1 准备三台装有zookeeper集群的主机(192.168.61.134,192.168.61.130,192.168.61.135),并启动zk。
    1.2 开发环境springboot,jkd1.8。
  2. 代码实现
    2.1 连接zk工具类
package com.my.zk.zookeeperdemo.conf;

import org.apache.zookeeper.ZooKeeper;

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

public class ZkUtils {
    private static ZooKeeper zk;
//    private static String zk_address = "192.168.61.134:2181,192.168.61.130:2181,192.168.61.135:2181/testConf";
    private static String zk_address = "192.168.61.134:2181,192.168.61.130:2181,192.168.61.135:2181/testLock";
    private static DefaultWatch defaultWatch = new DefaultWatch();
    //countDonwLatch是为了保证zk连接成功后返回可用的zk对象,连接成功之前阻塞
    private static CountDownLatch init = new CountDownLatch(1);
    public static  ZooKeeper getZk(){
        try {
            zk = new ZooKeeper(zk_address,1000,defaultWatch);
            defaultWatch.setCc(init);
            init.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return zk;
    }
}

2.2 监控zk连接的Watch

package com.my.zk.zookeeperdemo.conf;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import java.util.concurrent.CountDownLatch;

public class DefaultWatch implements Watcher {
    CountDownLatch cc;
    public void setCc(CountDownLatch cc){
        this.cc = cc;

    }
    @Override
    public void process(WatchedEvent watchedEvent) {
        switch(watchedEvent.getState()){

            case Unknown:
                break;
            case Disconnected:
                break;
            case NoSyncConnected:
                break;
            case SyncConnected:
                //连接成功后减一,执行Zkutils中的await()方法
                cc.countDown();
                break;
            case AuthFailed:
                break;
            case ConnectedReadOnly:
                break;
            case SaslAuthenticated:
                break;
            case Expired:
                break;
        }
    }
}

2.3 监控节点状态的Watch

package com.my.zk.zookeeperdemo.lock;

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

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

public class WatchCallBack implements Watcher, AsyncCallback.StringCallback, AsyncCallback.ChildrenCallback , AsyncCallback.StatCallback {
    ZooKeeper zk;
    String threadName;
    CountDownLatch cc = new CountDownLatch(1);
    String childrenPathName;//格式如:/lock0000000010

    public String getChildrenPathName() {
        return childrenPathName;
    }

    public void setChildrenPathName(String childrenPathName) {
        this.childrenPathName = childrenPathName;
    }

    public String getThreadName() {
        return threadName;
    }

    public void setThreadName(String threadName) {
        this.threadName = threadName;
    }

    public ZooKeeper getZk() {
        return zk;
    }

    public void setZk(ZooKeeper zk) {
        this.zk = zk;
    }

    public void tryLock(){
        try {
            //创建有序的临时节点
            zk.create("/lock",threadName.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL,this,"aaa");
            cc.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public void unLock(){
        try {
            zk.delete(childrenPathName,-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void process(WatchedEvent watchedEvent) {
        switch (watchedEvent.getType()) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                zk.getChildren("/",false,this,"jij");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
        }
    }
//    create callback
    @Override
    public void processResult(int i, String s, Object o, String s1) {
        System.out.println(this.getThreadName()+ " node:"+s1);
//        如果节点创建成功
        childrenPathName = s1;
        if (null != s1){
//            检索/testLock根节点下的孩子,即每个/lock
//            父节点不需要监控,所以第二个参数用false,这里仅仅获取children就足够了
            zk.getChildren("/",false,this,"bbb");

        }

    }
//    getChildren callback
    @Override
    public void processResult(int i, String s, Object o, List<String> list) {
//        zookeeper返回的序列节点的集合是乱序的,所以需要排序
        Collections.sort(list);
//        list中的每个children的格式如lock0000000010,没有"/",所以要截取再比较
        int index = list.indexOf(childrenPathName.substring(1));
        if (0 == index){
            System.out.println(threadName+" i am first.....");
            cc.countDown();
        }else {
            zk.exists("/"+list.get(index-1),this,this,"sss");

        }
    }
//    exists callback
    @Override
    public void processResult(int i, String s, Object o, Stat stat) {

    }
}

2.4 测试类

package com.my.zk.zookeeperdemo;

import com.my.zk.zookeeperdemo.conf.ZkUtils;
import com.my.zk.zookeeperdemo.lock.WatchCallBack;
import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Test;

import static org.springframework.test.context.transaction.TestTransaction.start;

public class ZkLockTests {
    ZooKeeper zk;

    @After
    public void over(){
        try {
            zk.close();
            System.out.println("关闭zk连接。。。。。。");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testZkLock(){
        zk  = ZkUtils.getZk();
        //模拟抛出十个线程
        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                WatchCallBack watchCallBack = new WatchCallBack();
                watchCallBack.setZk(zk);
                String threadName = Thread.currentThread().getName();
                System.out.println(threadName+"线程已被创建————————————");
                watchCallBack.setThreadName(threadName);
                //抢锁
                watchCallBack.tryLock();
                //干活
                System.out.println(threadName +"working......");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //释放锁
                watchCallBack.unLock();
            }).start();
        }
        while (true){

        }
    }
}
  1. 监控根节点/testLock下十个临时有序节点从有到无(锁释放)的过程,实际上刚开始是十个临时有序节点
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值