IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 14 Zookeeper案例:分布式配置注册发现、分布式锁、ractive模式编程 -> 正文阅读

[大数据]14 Zookeeper案例:分布式配置注册发现、分布式锁、ractive模式编程

分布式配置

在这里插入图片描述

连接ZK集群

ZK 工具类(ZKUtils.java):

package org.garen.study.config;

import org.apache.zookeeper.ZooKeeper;

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

/**
 * ZK 工具类
 *
 * 1、创建连接,返回ZK连接对象
 */
public class ZKUtils {

    /**
     * zk连接对象
     */
    private static ZooKeeper zk;

    /**
     * 连接ZK集群的字符串,指定了父目录为 "/testConf"
     */
    private static String connectString = "192.168.174.62:2181,192.168.174.63:2181,192.168.174.64:2181,192.168.174.62:2181/testConf";

    /**
     * 创建连接的watch
     * defaultWatch,创建连接传入的watch,这个watch,session级别的,跟path、node没有关系。
     */
    private static DefaultWatch defaultWatch = new DefaultWatch();

    /**
     * 阻塞对象
     */
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    /**
     * 创建连接,返回连接对象
     */
    public static ZooKeeper getZK() {
        try {
            // 创建连接对象,传入“连接ZK集群的字符串”、session超时时间、“创建连接的watch”
            zk = new ZooKeeper(connectString, 1000, defaultWatch);
            // 创建连接的watch对象传入“阻塞对象”
            defaultWatch.setCountDownLatch(countDownLatch);     // set countDownLatch
            // 阻塞,直到ZK连接对象创建完成
            countDownLatch.await();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        // 返回连接对象
        return zk;
    }
}

创建连接的watch(DefaultWatch.java)

package org.garen.study.config;

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

import java.util.concurrent.CountDownLatch;

/**
 * 创建连接的watch
 * defaultWatch,创建连接传入的watch,这个watch,session级别的,跟path、node没有关系。
 */
public class DefaultWatch implements Watcher {

    /**
     * 阻塞对象
     */
    CountDownLatch countDownLatch;

    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    /**
     * DefaultWatch 的回调方法
     * @param event 事件
     */
    @Override
    public void process(WatchedEvent event) {

        // defaultWatch触发回调,打印事件信息
        System.out.println("Connect zk cluster, create zk watch: " + event.toString());

        // 遍历时间状态
        switch (event.getState()) {
            case Unknown:
                break;
            case Disconnected:
                break;
            case NoSyncConnected:
                break;
            case SyncConnected:
                // 连接成功,结束阻塞
                countDownLatch.countDown();
                break;
            case AuthFailed:
                break;
            case ConnectedReadOnly:
                break;
            case SaslAuthenticated:
                break;
            case Expired:
                break;
            case Closed:
                break;
        }
    }
}

测试

测试类(TestConfig.java):
其中conn()方法,创建连接,返回连接对象,见前面“连接ZK集群”章节的代码

package org.garen.study.config;

import org.apache.zookeeper.ZooKeeper;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * 分布式配置,测试类
 */
public class TestConfig {

    // ZK集群连接对象
    ZooKeeper zk;

    /**
     * 运行测试方法前,创建ZK集群连接,获得连接对象
     */
    @Before
    public void conn() {
        zk = ZKUtils.getZK();   // 创建连接,返回连接对象
    }

    /**
     * 结束测试方法后,关闭ZK集群连接
     */
    @After
    public void close() {
        try {
            zk.close();     // 关闭ZK集群连接
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 分布式配置,测试方法
     */
    @Test
    public void getConf() {
        // 配置文件对象类
        MyConf myConf = new MyConf();
        // 回调方法工具类
        WatchCallBack watchCallBack = new WatchCallBack();
        watchCallBack.setZk(zk);    // ZK连接对象赋值
        watchCallBack.setMyConf(myConf);    // 配置文件对象赋值
        // 阻塞,直到myConf有值,结束阻塞,程序继续向下执行
        // 情况1:节点存在
        // 情况2:节点不存在
        // 情况3:节点不存在,阻塞,然后,节点被创建了
        // 情况4:节点存在,节点被改变了
        // 情况5:节点存在,然后节点被删除了
        watchCallBack.awaitMyConf();

        // 死循环,打印配置
        while (true) {
            // 配置为空(节点被删除了,配置清空了)
            if(myConf.getConf() == null)
            {
                System.out.println("no conf ...");      // 打印没有配置的消息
                watchCallBack.awaitMyConf();    // 阻塞,直到myConf有值,结束阻塞,程序继续向下执行
            }
            // 配置不为空
            else
            {
                System.out.println(myConf.getConf());   // 打印配置信息
            }
            // 每次循环,睡2秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}

配置文件对象类(MyConf.java)

package org.garen.study.config;

/**
 * 配置文件对象类
 */
public class MyConf {
    /**
     * 配置的一个字符串属性
     */
    private String conf;

    public String getConf() {
        return conf;
    }

    public void setConf(String conf) {
        this.conf = conf;
    }
}

回调方法工具类(WatchCallBack.java)

package org.garen.study.config;

import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.CountDownLatch;

/**
 * 回调方法工具类
 *
 * Watcher 的回调方法
 * AsyncCallback.StatCallback 的回调方法
 * AsyncCallback.DataCallback 的回调方法
 */
public class WatchCallBack implements Watcher, AsyncCallback.StatCallback, AsyncCallback.DataCallback {

    /**
     * ZK连接对象
     */
    ZooKeeper zk;

    /**
     * 配置文件对象
     */
    MyConf myConf;

    /**
     * 阻塞对象
     */
    CountDownLatch countDownLatch = new CountDownLatch(1);

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

    public void setMyConf(MyConf myConf) {
        this.myConf = myConf;
    }

    /**
     * 阻塞,直到 myConf有值,结束阻塞,程序继续向下执行
     *
     * 情况1:节点存在
     * watcher没有被触发
     * 执行回调方法 cb: this -> AsyncCallback.StatCallback
     *
     * 情况2:节点不存在
     * watcher没有被触发
     * 执行回调方法 cb: this -> AsyncCallback.StatCallback
     *
     * 情况3:节点不存在,阻塞,然后,节点被创建了
     * watcher被触发
     * 创建走NodeCreated
     *
     * 情况4:节点存在,节点被改变了
     * 节点存在,同情况1
     * 节点被改变了,watcher被触发
     * 改变走NodeDataChanged
     *
     * 情况5:节点存在,然后节点被删除了
     * 节点存在,同情况1
     * 节点被删除了,watcher被触发
     * 删除走NodeDeleted,然后清空配置,重新创建阻塞对象,再调awaitMyConf()方法又会被阻塞
     */
    public void awaitMyConf() {
        // 节点是否存在
        // 异步方法,通过回调处理结果,cb: this -> AsyncCallback.StatCallback 的回调方法 processResult
        // 观察节点,如果发生变化,则通过watcher处理,watcher: this -> Watcher 的回调方法 process
        zk.exists("/AppConf", this, this, "ABC");
        try {
            countDownLatch.await();     //阻塞
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Watcher 的回调方法
     * @param event 事件
     */
    @Override
    public void process(WatchedEvent event) {
        switch (event.getType()) {
            case None:
                break;
            case NodeCreated:
                // 节点被创建
                // 查询节点值,通过回调处理结果,cb: this -> AsyncCallback.DataCallback 的回调方法 processResult
                // 观察节点,如果发生变化,则通过watcher处理,watcher: this -> Watcher 的回调方法 process
                zk.getData("/AppConf", this, this, "BCD");
                break;
            case NodeDeleted:
                // 节点被删除了
                // 清空配置
                myConf.setConf(null);
                // 重新创建阻塞对象,再调awaitMyConf()方法又会被阻塞
                countDownLatch = new CountDownLatch(1);
                break;
            case NodeDataChanged:
                // 节点值被修改了
                // 重新查询节点值,通过回调处理结果,cb: this -> AsyncCallback.DataCallback 的回调方法 processResult
                // 观察节点,如果发生变化,则通过watcher处理,watcher: this -> Watcher 的回调方法 process
                zk.getData("/AppConf", this, this, "BCD");
                break;
            case NodeChildrenChanged:
                break;
            case DataWatchRemoved:
                break;
            case ChildWatchRemoved:
                break;
        }
    }

    /**
     * AsyncCallback.StatCallback 的回调方法
     *
     * 情况1:节点存在
     * stat != null
     * 查询节点值zk.getData,走回调处理结果;添加watcher,如果节点发生变化,触发watcher
     *
     * 情况2:节点不存在,stat为空,什么都不做
     *
     *
     * @param rc
     * @param path
     * @param ctx
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        if(stat != null){
            zk.getData("/AppConf", this, this, "BCD");
        }
    }

    /**
     * AsyncCallback.DataCallback 的回调方法
     *
     * 情况1:节点值不为空
     * data != null
     * 节点值存入配置,结束阻塞
     *
     * 情况2:节点值为空
     * data == null
     * 什么都不做
     *
     * @param rc
     * @param path
     * @param ctx
     * @param data
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
        if(data != null){
            String s = new String(data);
            myConf.setConf(s);
            // 结束阻塞
            countDownLatch.countDown();
        }
    }

}

运行代码进行测试

  • 节点存在
    在这里插入图片描述
    在这里插入图片描述
  • 删除节点
    在这里插入图片描述
    在这里插入图片描述
  • 创建节点
    在这里插入图片描述
    在这里插入图片描述
  • 修改节点
    在这里插入图片描述
    在这里插入图片描述

分布式锁

在这里插入图片描述

连接ZK集群

ZK 工具类(ZKUtils.java):
延用“分布式配置”中的ZKUtils.java,连接ZK集群的字符串,父节点改成了“/testLock”。

    /**
     * 连接ZK集群的字符串,指定了父目录为 "/testConf"
     */
//    private static String connectString = "192.168.174.62:2181,192.168.174.63:2181,192.168.174.64:2181,192.168.174.62:2181/testConf";
    /**
     * 连接ZK集群的字符串,指定了父目录为 "/testLock"
     */
    private static String connectString = "192.168.174.62:2181,192.168.174.63:2181,192.168.174.64:2181,192.168.174.62:2181/testLock";

创建连接的watch(DefaultWatch.java)
延用“分布式配置”中的DefaultWatch.java,没有任何改变。

测试

测试类(TestLock.java):
其中conn()方法,创建连接,返回连接对象,见前面“连接ZK集群”章节的代码。

package org.garen.study.lock;

import org.apache.zookeeper.ZooKeeper;
import org.garen.study.config.ZKUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.stream.IntStream;

/**
 * 分布式锁,测试类
 */
public class TestLock {

    // ZK集群连接对象
    ZooKeeper zk;

    /**
     * 运行测试方法前,创建ZK集群连接,获得连接对象
     */
    @Before
    public void conn() {
        zk = ZKUtils.getZK();   // 创建连接,返回连接对象
    }

    /**
     * 结束测试方法后,关闭ZK集群连接
     */
    @After
    public void close() {
        try {
            zk.close();     // 关闭ZK集群连接
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 分布式锁,测试方法
     */
    @Test
    public void testLock() {

        // 循环10次,创建10个线程
        IntStream.range(0, 10).forEach(i -> {
            // 每次循环,创建1个线程
            new Thread(() -> {
                // 当前线程名称
                String threadName = Thread.currentThread().getName();
                // 回调方法工具类
                WatchCallBack watchCallBack = new WatchCallBack();
                watchCallBack.setZk(zk);    // ZK连接对象赋值
                watchCallBack.setThreadName(threadName);    // 线程名称赋值
                // 枪锁
                watchCallBack.tryLock();
                // 干活
                System.out.println(threadName + "working...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 释放锁
                watchCallBack.unLock();
            }).start();
        });

        // 主线程不停
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


}

回调方法工具类(WatchCallBack.java)

package org.garen.study.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.Children2Callback, AsyncCallback.StatCallback {
    /**
     * ZK连接对象
     */
    ZooKeeper zk;

    public ZooKeeper getZk() {
        return zk;
    }

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

    /**
     * 线程名称
     */
    String threadName;

    public String getThreadName() {
        return threadName;
    }

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

    /**
     * 阻塞对象
     */
    CountDownLatch countDownLatch = new CountDownLatch(1);

    /**
     * 每个线程创建的,以"/lock"开头的,序列化临时节点,的路径
     */
    String pathName;

    public String getPathName() {
        return pathName;
    }

    public void setPathName(String pathName) {
        this.pathName = pathName;
    }

    /**
     * 抢锁
     *
     * 在父节点("/testLock")下创建以"/lock"开头的序列化临时节点
     * 阻塞
     *
     * 后续方法,看 -> zk.create 的回调
     */
    public void tryLock() {
        try {
            System.out.println(threadName + " create....");
            // 在父节点("/testLock")下创建以"/lock"开头的序列化临时节点
            zk.create("/lock", threadName.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL, this, "abc");
            // 阻塞
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放锁
     *
     * 删除,当前线程创建的,以"/lock"开头的,序列化临时节点
     *
     * 后续方法,看 -> Watcher 的回调方法(是第一个节点)
     */
    public void unLock() {
        try {
            zk.delete(pathName, -1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }



    /**
     * Watcher 的回调方法
     * 监控删除事件
     *
     * 如果第一个节点,也就是锁释放了,其实只有第二个节点收到了回调事件!
     *
     * 如果,不是第一个节点,某一个线程挂了(临时节点,客户端session会话结束就消失了),
     * 也能造成他后面的收到这个通知,从而让他后面那个节点去watch挂掉这个节点前边的。
     *
     * @param event
     */
    @Override
    public void process(WatchedEvent event) {
        switch (event.getType()) {
            case None:
                break;
            case NodeCreated:
                break;
            case NodeDeleted:
                // 查询子节点,不监控,回调方法处理结果
                // 后续方法,看 ->zk.getChildren 的回调方法
                zk.getChildren("/", false, this, "sdf");
                break;
            case NodeDataChanged:
                break;
            case NodeChildrenChanged:
                break;
            case DataWatchRemoved:
                break;
            case ChildWatchRemoved:
                break;
        }
    }


    /**
     * AsyncCallback.StringCallback 的回调方法
     * zk.create的回调方法
     *
     * 打印消息:哪个线程,创建了哪个节点
     * 给pathName赋值
     * 查询子节点,不监控,回调方法处理结果
     *
     * 后续方法,看 -> zk.getChildren 的回调
     *
     * @param rc
     * @param path
     * @param ctx
     * @param name
     */
    @Override
    public void processResult(int rc, String path, Object ctx, String name) {
        // 获得锁要看自己是不是最小的
        // 监控前一个,所以父节点不需要watcher
        if(name != null){
            System.out.println(threadName + "create node : " + name);
            pathName = name;
            // 查询子节点,不监控,回调方法处理结果
            zk.getChildren("/", false, this, "sdf");
        }
    }

    /**
     * AsyncCallback.Children2Callback 的回调方法
     * zk.getChildren的回调
     *
     * 排序子节点,然后查询当前线程创建的节点,在子节点集合中的排序
     * 如果排序为0(第一个节点),则抢到锁,结束阻塞
     *      后续方法,看 -> 测试方法 testLock() 中 watchCallBack.tryLock() 抢锁之后的代码
     * 如果排序不是0(不是第一个节点),则没有抢到锁,通过调用zk.exists方法上,给前一个节点加上监控watch
     *      后续方法,看 -> Watcher 的回调方法(不是第一个节点)
     * @param rc
     * @param path
     * @param ctx
     * @param children 每个线程创建的,以"/lock"开头的,序列化临时节点的集合
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {
        // 一定能看到自己前面的

//        System.out.println(threadName + "look locks ...");
//        for (String child : children) {
//            System.out.println(child);
//        }

        // children 排序
        Collections.sort(children);

        // pathName 当前线程,创建的,以"/lock"开头的,序列化临时节点
        // pathName.substring(1) 去掉"/" -> child
        // child 在 children 里的排序
        int i = children.indexOf(pathName.substring(1));

        // 是不是第一个,设定第一个抢到锁
        if(i == 0) {
            // 是第一个,抢到了锁
            System.out.println(threadName + " i am first ...");
            try {
                // 父节点("/testLock")的值,设置为:抢到锁的,线程的名称
                zk.setData("/", threadName.getBytes(), -1);
            } catch (KeeperException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 抢到锁的线程,结束阻塞
            countDownLatch.countDown();
        }else {
            // 不是第一个,没有抢到锁
            // 前一个节点是否存在,回调方法
            // 增加对前一个节点的监控
            zk.exists("/" + children.get(i-1), this, this, "ggg");
        }
    }

    /**
     * AsyncCallback.StatCallback 的回调方法
     * zk.exists 的回调方法
     * 前一个节点是否存在
     *
     * @param rc
     * @param path
     * @param ctx
     * @param stat
     */
    @Override
    public void processResult(int rc, String path, Object ctx, Stat stat) {
        System.out.println("last node exists : [" + "rc:" + rc + ", path: " + path + ", ctx: " + ctx + ", stat: " + stat + "]");
    }
}

运行代码进行测试

  • 运行前
    在这里插入图片描述

  • 运行结果

D:\GarenGosling\Java\jdk1.8.0_291\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:D:\GarenGosling\JetBrains\IntelliJ IDEA Educational Edition 2020.2.1\lib\idea_rt.jar=51228:D:\GarenGosling\JetBrains\IntelliJ IDEA Educational Edition 2020.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\GarenGosling\JetBrains\IntelliJ IDEA Educational Edition 2020.2.1\lib\idea_rt.jar;D:\GarenGosling\JetBrains\IntelliJ IDEA Educational Edition 2020.2.1\plugins\junit\lib\junit5-rt.jar;D:\GarenGosling\JetBrains\IntelliJ IDEA Educational Edition 2020.2.1\plugins\junit\lib\junit-rt.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\charsets.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\deploy.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\access-bridge-64.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\cldrdata.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\dnsns.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\jaccess.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\jfxrt.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\localedata.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\nashorn.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\sunec.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\sunjce_provider.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\sunmscapi.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\sunpkcs11.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\ext\zipfs.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\javaws.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\jce.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\jfr.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\jfxswt.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\jsse.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\management-agent.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\plugin.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\resources.jar;D:\GarenGosling\Java\jdk1.8.0_291\jre\lib\rt.jar;D:\GarenGosling\workspace\idea_study\study-03\target\test-classes;D:\GarenGosling\workspace\idea_study\study-03\target\classes;D:\GarenGosling\apache-maven-3.6.3\repo\junit\junit\4.11\junit-4.11.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\apache\zookeeper\zookeeper\3.5.9\zookeeper-3.5.9.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\apache\zookeeper\zookeeper-jute\3.5.9\zookeeper-jute-3.5.9.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\apache\yetus\audience-annotations\0.5.0\audience-annotations-0.5.0.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-handler\4.1.50.Final\netty-handler-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-common\4.1.50.Final\netty-common-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-resolver\4.1.50.Final\netty-resolver-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-buffer\4.1.50.Final\netty-buffer-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-transport\4.1.50.Final\netty-transport-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-codec\4.1.50.Final\netty-codec-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-transport-native-epoll\4.1.50.Final\netty-transport-native-epoll-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\io\netty\netty-transport-native-unix-common\4.1.50.Final\netty-transport-native-unix-common-4.1.50.Final.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;D:\GarenGosling\apache-maven-3.6.3\repo\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;D:\GarenGosling\apache-maven-3.6.3\repo\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 org.garen.study.lock.TestLock,testLock
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Connect zk cluster, create zk watch: WatchedEvent state:SyncConnected type:None path:null
Thread-1 create....
Thread-4 create....
Thread-5 create....
Thread-0 create....
Thread-9 create....
Thread-8 create....
Thread-7 create....
Thread-3 create....
Thread-2 create....
Thread-6 create....
Thread-3create node : /lock0000000030
Thread-4create node : /lock0000000031
Thread-7create node : /lock0000000032
Thread-6create node : /lock0000000033
Thread-8create node : /lock0000000034
Thread-0create node : /lock0000000035
Thread-5create node : /lock0000000036
Thread-2create node : /lock0000000037
Thread-9create node : /lock0000000038
Thread-1create node : /lock0000000039
Thread-3 i am first ...
Thread-3working...
last node exists : [rc:0, path: /lock0000000030, ctx: ggg, stat: 42949673243,42949673243,1627737835099,1627737835099,0,0,0,0,8,0,42949673243
]
last node exists : [rc:0, path: /lock0000000031, ctx: ggg, stat: 42949673244,42949673244,1627737835100,1627737835100,0,0,0,0,8,0,42949673244
]
last node exists : [rc:0, path: /lock0000000032, ctx: ggg, stat: 42949673245,42949673245,1627737835101,1627737835101,0,0,0,0,8,0,42949673245
]
last node exists : [rc:0, path: /lock0000000033, ctx: ggg, stat: 42949673246,42949673246,1627737835101,1627737835101,0,0,0,0,8,0,42949673246
]
last node exists : [rc:0, path: /lock0000000034, ctx: ggg, stat: 42949673247,42949673247,1627737835101,1627737835101,0,0,0,0,8,0,42949673247
]
last node exists : [rc:0, path: /lock0000000035, ctx: ggg, stat: 42949673248,42949673248,1627737835101,1627737835101,0,0,0,0,8,0,42949673248
]
last node exists : [rc:0, path: /lock0000000036, ctx: ggg, stat: 42949673249,42949673249,1627737835101,1627737835101,0,0,0,0,8,0,42949673249
]
last node exists : [rc:0, path: /lock0000000037, ctx: ggg, stat: 42949673250,42949673250,1627737835101,1627737835101,0,0,0,0,8,0,42949673250
]
last node exists : [rc:0, path: /lock0000000038, ctx: ggg, stat: 42949673251,42949673251,1627737835101,1627737835101,0,0,0,0,8,0,42949673251
]
Thread-4 i am first ...
Thread-4working...
Thread-7 i am first ...
Thread-7working...
Thread-6 i am first ...
Thread-6working...
Thread-8 i am first ...
Thread-8working...
Thread-0 i am first ...
Thread-0working...
Thread-5 i am first ...
Thread-5working...
Thread-2 i am first ...
Thread-2working...
Thread-9 i am first ...
Thread-9working...
Thread-1 i am first ...
Thread-1working...

Process finished with exit code -1

  • 运行中
    在这里插入图片描述
  • 运行后
    在这里插入图片描述

至此,本专栏结束!


上一篇《13 Zookeeper原理知识,paxos、zab、角色功能、API开发基础》

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:34:51  更:2021-08-01 14:34:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 11:05:58-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码