本文涉及到几个zookeeper简单的知识点,永久节点、有序节点、watch机制。比较基础,熟悉的就别看了跳过这篇吧

  • 每个线程在/locks节点下创建一个临时有序节点test_lock_0000000040
  • 获得/locks节点下所有子节点A、B、C,排序获得最小值
  • 若当前节点B为最小值则获得锁,执行业务逻辑
  • 若当前节点B不是最小值则watch比自己小1的节点A,节点A存在则await,否则获得锁

总结:临时有序节点排序后watch比自己小1的节点。

下面看代码

1.线程初始化

创建一个名字为lockName的永久节点(只有永久节点才可以创建子节点)

DistributedLock(String url, String lockName) {
    this.lockName = lockName;
    try {
        zkConn = new ZooKeeper(url, sessionTimeout, this);
        if (zkConn.exists(ROOT_LOCK, false) == null)
            zkConn.create(ROOT_LOCK, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    } catch (IOException | InterruptedException | KeeperException e) {
        e.printStackTrace();
    }
}

复习一下:zookeeper的节点有以下几种类型:永久,永久有序,临时,临时有序

public enum CreateMode {
    PERSISTENT(0, false, false),
    PERSISTENT_SEQUENTIAL(2, false, true),
    EPHEMERAL(1, true, false),
    EPHEMERAL_SEQUENTIAL(3, true, true);

2.线程尝试获得锁tryLock

创建临时有序节点,会在你的lockName后面加上一串编号,例如/locks/test_lock_0000000035

CURRENT_LOCK = zkConn.create(ROOT_LOCK + "/" + lockName + splitStr, new byte[0],
        ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

获取当前lockName下的所有子临时节点

List<String> subNodes = zkConn.getChildren(ROOT_LOCK, false);

把名字都取出来放进list排个序

List<String> lockObjects = new ArrayList<>();
for (String node : subNodes) {
    String _node = node.split(splitStr)[0];
    if (_node.equals(lockName)) lockObjects.add(node);
}

若当前节点为最小节点,则直接获取锁成功

if (CURRENT_LOCK.equals(ROOT_LOCK + "/" + lockObjects.get(0))) {
    return true;
}

若不是最小节点,开始等待,见下一步。

3.开始等待锁

获得当前线程需要等待的节点名

  • 获得当前节点的节点名即test_lock_0000000035
  • 获得当前几点在所有排队等锁的线程中的排序
  • 根据排序-1,获得排在自己前面的线程的节点名
String prevNode = CURRENT_LOCK.substring(CURRENT_LOCK.lastIndexOf("/") + 1);
int prevNodePosition = Collections.binarySearch(lockObjects, prevNode);
WAIT_LOCK = lockObjects.get(prevNodePosition - 1);

给exists加上watcher,监控当前线程等待的节点waitLock是否还存在

若存在即stat不为null,当前线程先开始await

同时watch线程也启动了开始监控exists操作

若是exists状态有变化了(即waitLock不存在了)触发watch线程的countDown操作。

countDown操作使当前线程结束waiting,获得锁,开始继续往后执行

private boolean waitForLock(String waitLock, long waitTime) throws KeeperException, InterruptedException {
    Stat stat = zkConn.exists(ROOT_LOCK + "/" + waitLock, new Watcher() {
        @Override
        public void process(WatchedEvent watchedEvent) {
            if (countDownLatch != null) {
                countDownLatch.countDown();
            }
        }
    });
    if (stat != null) {
        System.out.println(Thread.currentThread().getName() + " is waiting for " + ROOT_LOCK + "/" + waitLock);
        this.countDownLatch = new CountDownLatch(1);
        this.countDownLatch.await(waitTime, TimeUnit.MILLISECONDS);
        this.countDownLatch = null;
        System.out.println(Thread.currentThread().getName() + " get the lock ");
    }
    return true;
}

完整的代码可以在我的公众号后台回复9获得,感谢阅读。

zookeeper-分布式锁的代码实现-【每日五分钟搞定大数据】的更多相关文章

  1. zookeeper核心-zab协议-《每日五分钟搞定大数据》

    上篇文章<paxos与一致性>说到zab是在paxos的基础上做了重要的改造,解决了一系列的问题,这一篇我们就来说下这个zab. zab协议的全称是ZooKeeper Atomic Bro ...

  2. zookeeper-架构设计与角色分工-《每日五分钟搞定大数据》

    本篇文章阅读时间5分钟左右 点击看<每日五分钟搞定大数据>完整思维导图   zookeeper作为一个分布式协调系统,很多组件都会依赖它,那么此时它的可用性就非常重要了,那么保证可用性的同 ...

  3. HDFS-异常大全-《每日五分钟搞定大数据》

    点击看<每日五分钟搞定大数据>完整思维导图以及所有文章目录 问题1:Decomminssioning退役datanode(即删除节点) 1.配置exclude: <name>d ...

  4. zookeeper-操作与应用场景-《每日五分钟搞定大数据》

    Zookeeper作为一个分布式协调系统提供了一项基本服务:分布式锁服务,分布式锁是分布式协调技术实现的核心内容.像配置管理.任务分发.组服务.分布式消息队列.分布式通知/协调等,这些应用实际上都是基 ...

  5. zookeeper-如何修改源码-《每日五分钟搞定大数据》

    本篇文章仅仅是起一个抛砖迎玉的作用,举一个如何修改源码的例子.文章的灵感来自 ZOOKEEPER-2784. 提一个问题先 之前的文章讲过zxid的设计,我们先复习下: zxid有64位,分成两部分: ...

  6. zookeeper-监控与优化-《每日五分钟搞定大数据》

    本文的命令和配置都是基于zookeeper-3.4.6版本.优化很多时候都是基于监控的,所以把这两个内容写在了一起,慢慢消化. 监控 简单地说,监控无非就是获取服务的一些指标,再根据实际业务情况给这些 ...

  7. redis- info调优入门-《每日五分钟搞定大数据》

    本文根据redis的info命令查看redis的内存使用情况以及state状态,来观察redis的运行情况以及需要作出的相应优化. info 1.memory used_memory:13409011 ...

  8. 五分钟搞定Go.js

    五分钟搞定Go.js  1.基于html5~因为Go.js是一个依赖于HTML5特性的JavaScript库,所以需要确保您的页面声明它是一个HTML5文档,当然需要加载库 <!DOCTYPE ...

  9. 五分钟搞定Linux容器

    [TechTarget中国原创] Linux容器针对特定工作负载提供了全新的灵活性与可能性.存在很多解决方案,但是没有一个解决方案能够像systemd容器那样进行快速部署.给我五分钟,本文将介绍如何使 ...

随机推荐

  1. 【Linux高频命令专题(24)】grep

    简述 Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则 ...

  2. [20181225]12CR2 SQL Plan Directives.txt

    [20181225]12CR2 SQL Plan Directives.txt --//12C引入SQL PLAN Directives.12cR1版本会造成大量的动态取样,影响性能.许多人把OPTI ...

  3. 5. svg学习笔记-坐标系变换

    之前我们编写图形元素的时候,编写好了位置大小就是固定的,通过坐标系变换,可以移动缩放,旋转图形,但必须声明的是,进行变换时是图形相对于坐标系的变化,就是图形是不发生变化的,而是坐标系发生了变化,比如缩 ...

  4. 将web项目部署到阿里云服务器上

    一.用eclipse将写好的项目打成war包 1.右键点击项目,选择Export 选择打包之后的路径,点击Finsh. 2.购买阿里云服务器 按下图选择 3.设置云服务器防火墙 4.远程连接云服务器 ...

  5. oracle 分组函数执行分析

    先上例了: select job as "JOB1", avg(sal) as "avg sal" from scott.emp group by " ...

  6. python中------decode解码出现的0xca问题解决方法

    一.错误: 解决方法: #源代码 data = sk.recv(1024) print(str(data,'gbk')) #修改代码 data = sk.recv(1024) print(str(da ...

  7. IIS 发布ASP.NET MVC 4.0 错误500.21解决办法

    由VS2013 写好的MVC 4.0 发布在服务器IIS 上报错500.21,解决办法:尝试多种网上介绍的办法,最后发现还是模块问题.

  8. 【项目 · Wonderland】会议一 · 可达鸭

    [软件工程实践 · 团队项目] 第一次作业 Part 0 · 简 要 目 录 Part 1 · 队 伍 阵 容 Part 2 · 会 议 记 录 相 关 Part 3 · 会 议 讨 论 记 录 Pa ...

  9. python3编写网络爬虫17-验证码识别

    一.验证码识别 1.图形验证码的识别 识别图形验证码需要 tesserocr 库 OCR技术识别(光学字符识别,是指通过扫描字符,然后通过其形状将其翻译成电子文本的过程.)例如 中国知网注册页面 ht ...

  10. Python闭包和装饰器再复习

    闭包 闭包的定义 在一个外函数中定义了一个内函数,并且内函数用到了外部函数的变量,而且外函数的返回值是内函数的引用,这就构成了一个闭包. 一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东 ...