• ZooKeeper 分布式锁 Curator 源码 03:可重入锁并发加锁


    前言

    在了解了加锁和锁重入之后,最需要了解的还是在分布式场景下或者多线程并发加锁是如何处理的?

    并发加锁

    先来看结果,在多线程对 /locks/lock_01 加锁时,是在后面又创建了新的临时节点。

    这块在加锁方法 CreateBuilderImpl#pathInForeground 中已经介绍过

    这里判断 /locks/lock_01 路径已经存在,会直接创建新的临时顺序节点。

    真正判断锁是否获取成功,其实是在 LockInternals#attemptLock 方法中的 internalLockLoop 方法中。

    加锁结果及监听

    internalLockLoop 方法的主要作用是判断加锁结果,以及获取锁失败时,对其他节点的监听。

    1. 获取父节点 /locks/lock_01 下的所有子节点,按照从小到大排序,判断自己是不是获取到锁,没有获取到就监听自己前一个节点;
    2. 支持设置超时时间,超时直接返回失败;
    3. 不支持设置超时时间或者还没有超时,则直接 wait 等待。

    是否获取锁的代码在 StandardLockInternalsDriver#getsTheLock

    这块就是判断是否为最小节点,因为在 getSortedChildren 中已经对所有节点排序,所以方法中的 List<String> children 是有序的。

    maxLeases 是在 InterProcessMutex 初始化的时候,指定的值为 1。

    最终这里的结果是,判断自己是不是最小,不是最小,就将 pathToWatch 设置为前一个节点

    只监听自己的前一个节点,可以避免羊群效应!

    为什么要进行等待呢?

    因为是为了防止无效自旋,因为这里有监听机制,会监听上一个节点是否释放。

    这块是 ZooKeeper 的 Watcher 监听机制,在节点释放的时候,会进行回调,然后使用 Java 的 notifyAll 方法通知所有的 wait 线程。然后这里的 while trye 会继续执行,重新检查是否获得锁等。

    总结

    本文主要介绍了基于 ZooKeeper 的分布式锁框架 Curator 在并发场景下的锁竞争问题。

    重点需要了解的是:

    1. 为了避免羊群效应,临时顺序节点,加锁失败后监听的是前一个节点
    2. 为了避免无效自旋,这里使用了 Java 的 wait/notifyAll 机制;
    3. 可以看出,默认加锁就是公平锁

    相关推荐

    作者: 刘志航

    公众号:『 程序员小航 』

    版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Notes

  • 相关阅读:
    大数据处理系列之(二)系统过载保护
    大数据处理系列之(一)Java线程池使用
    js实现递归菜单无限层
    treeTable实现排序
    spring-dm 一个简单的实例
    Equinox OSGi服务器应用程序的配置步骤 (支持JSP页面)
    Spring DM 2.0 环境配置 解决Log4j问题
    Spring.DM web开发环境搭建
    STL容器的排序
    排序例子
  • 原文地址:https://www.cnblogs.com/liuzhihang/p/15046079.html
Copyright © 2020-2023  润新知