ZooKeeper 分布式锁 Curator 源码之三:可重入锁并发加锁

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

[[410513]]

前言

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

1并发加锁

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

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

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

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

加锁结果及监听

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

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

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

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

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

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

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

为什么要进行等待呢?

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

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

2总结

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

重点需要了解的是:

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

本文转载自微信公众号「程序员小航」,可以通过以下二维码关注。转载本文请联系程序员小航公众号。

 

责任编辑:武晓燕 来源: 程序员小航
相关推荐

2021-07-08 09:21:17

ZooKeeper分布式锁 Curator

2021-07-09 06:48:31

ZooKeeperCurator源码

2021-06-27 21:24:55

RedissonJava数据

2021-07-16 07:57:34

ZooKeeperCurator源码

2021-06-30 14:56:12

Redisson分布式公平锁

2021-07-01 09:42:08

Redisson分布式

2021-07-03 17:45:57

分布式Redisson MultiLock

2022-01-14 08:35:58

Curator分布式锁Zookeeper

2020-06-15 08:15:47

分布式锁系统

2017-10-24 11:28:23

Zookeeper分布式锁架构

2021-10-25 10:21:59

ZK分布式锁ZooKeeper

2021-07-06 08:37:29

Redisson分布式

2020-11-16 12:55:41

Redis分布式锁Zookeeper

2021-02-28 07:49:28

Zookeeper分布式

2019-07-16 09:22:10

RedisZookeeper分布式锁

2021-07-02 08:51:09

Redisson分布式锁公平锁

2024-01-30 08:41:33

线程执行Redis分布式锁

2022-03-07 08:14:27

并发分布式

2022-03-11 10:03:40

分布式锁并发

2022-07-25 06:44:19

ZooKeeper分布式锁
点赞
收藏

51CTO技术栈公众号