原生 Zookeeper 实现分布式锁案例

//1.建立分布式锁的结构

java 复制代码
package zkcase2;

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

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

public class DistributedLock {

    private final ZooKeeper zooKeeper;
    private final String connection="hadoop102:2181,hadoop103:2181,hadoop104:2181"; //对应你服务器里面安装zk的节点,注意不可以有空格出现
    private final int sessiontimeout=2000;

    private CountDownLatch connect=new CountDownLatch(1);

    private CountDownLatch waitlath=new CountDownLatch(1);

    private String waitpath;
    private String currentnode;

    public DistributedLock() throws IOException, InterruptedException, KeeperException {

        //获取zk
        zooKeeper = new ZooKeeper(connection, sessiontimeout, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {

                //connect表示如果连接到zk 可以释放
                if (watchedEvent.getState()==Event.KeeperState.SyncConnected){
                    connect.countDown();
                }
                //waitlath需要释放
                if (watchedEvent.getType()==Event.EventType.NodeDeleted && watchedEvent.getPath().equals(waitpath)){
                    waitlath.countDown();
                }
            }
        });
        //等待zk正常连接之后往下进行
        connect.await();
        //判断根节点/locks是否存在
        Stat exists = zooKeeper.exists("/locks", false);
            if (exists==null){
                //如果状态为空说明根节点不存在,那就创建根节点
                zooKeeper.create("/locks","locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);


            }

    }

    //创建zk锁

    public void   zklock() throws InterruptedException {
        //创建对应的临时带序号节点

        try {
            currentnode = zooKeeper.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            //判断当前节点是不是最小的序号节点,如果是获取到锁,如果不是监听序号前一个节点
            List<String> children = zooKeeper.getChildren("/locks", false);

            //如果childern只有一个值那么就获取锁,如果有多个节点,判断谁最小
            if (children.size()==1){
                return;
            }else {
                Collections.sort(children);
                //获取节点名称seq-000000000000
                String thisnode = currentnode.substring("/locks/".length());
                //通过seq-000000000获取当前节点在childen当中的位置
                int indexOf = children.indexOf(thisnode);
                //判断
                if (indexOf==-1){
                    System.out.println("数据异常");
                } else if (indexOf==0) {
                    //只有一个节点直接获取锁
                    return;

                }else {
                    //不是只有一个节点所以需要监听他前一个节点
                    waitpath="/locks/"+children.get(indexOf-1);
                    zooKeeper.getData(waitpath,true,null);
                    //等待监听
                    waitlath.await();
                }
            }

        } catch (KeeperException e) {
            throw new RuntimeException(e);
        }

    }
    //解锁
    public void unzklock(){
        //删除节点
        try {
            zooKeeper.delete(currentnode,-1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (KeeperException e) {
            throw new RuntimeException(e);
        }

    }
}

//2.建立测试类

java 复制代码
package zkcase2;

import org.apache.zookeeper.KeeperException;

import java.io.IOException;

public class DistributedLockTest {
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
      final   DistributedLock distributedLock1 = new DistributedLock();


        final   DistributedLock distributedLock2 = new DistributedLock();


        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    distributedLock1.zklock();

                    System.out.println("线程1启动,获取到锁");

                    Thread.sleep(5*1000);

                    distributedLock1.unzklock();
                    System.out.println("线程1释放锁");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    distributedLock2.zklock();

                    System.out.println("线程2启动,获取到锁");

                    Thread.sleep(5*1000);

                    distributedLock2.unzklock();
                    System.out.println("线程2释放锁");
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}
相关推荐
程序员吕洞宾7 分钟前
开源多维表格SmartTable V1.6.1:工作流画布,让自动化工作流配置更直观、更方便
java·开源·自动化
董可伦11 分钟前
Spark 源码 | SparkSubmitArguments 参数解析(三)
大数据·分布式·spark
我登哥MVP13 分钟前
走进 Gang of Four 设计模式:访问者模式
java·设计模式·访问者模式·原型模式
雪碧聊技术15 分钟前
一文深入理解 Java 函数式编程思想
java·函数式编程
AIGS00119 分钟前
突破语义鸿沟:从向量空间JBoltAI看企业大脑构建逻辑
java·大数据·人工智能·人工智能ai大模型应用
琢磨先生David25 分钟前
OpenJDK 与 Oracle JDK 完整区别
java
倔强的石头10629 分钟前
企业智能设备运维管理系统:靠飞算 JavaAI,告别 Java 低效搬砖日常
java
深盾科技_Virbox40 分钟前
软件授权工具静默安装实践
java·运维·数据库·安全·软件需求
qq_452396231 小时前
第二篇:《Jenkins 从零搭建:安装、配置与第一个 Pipeline》
java·运维·jenkins
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题 第172题】【07_Redis篇】第8题:`setnx` 做分布式锁存在的问题
java·redis·分布式锁·死锁·setnx