Zookeeper 分布式锁 (图解+秒懂+史上最全) (5)

img

他的上一个顺序节点,不就是下面这个吗?

img

即客户端A创建的那个顺序节点!

所以,客户端B会对:

img

这个节点加一个监听器,监听这个节点是否被删除等变化!大家看下面的图。

在这里插入图片描述

接着,客户端A加锁之后,可能处理了一些代码逻辑,然后就会释放锁。那么,释放锁是个什么过程呢?

其实很简单,就是把自己在zk里创建的那个顺序节点,也就是:

img

这个节点给删除。

删除了那个节点之后,zk会负责通知监听这个节点的监听器,也就是客户端B之前加的那个监听器,说:兄弟,你监听的那个节点被删除了,有人释放了锁。

在这里插入图片描述

此时客户端B的监听器感知到了上一个顺序节点被删除,也就是排在他之前的某个客户端释放了锁。

客户端B抢锁成功

此时,就会通知客户端B重新尝试去获取锁,也就是获取"my_lock"节点下的子节点集合,此时为:

img

集合里此时只有客户端B创建的唯一的一个顺序节点了!

然后呢,客户端B判断自己居然是集合中的第一个顺序节点,bingo!可以加锁了!直接完成加锁,运行后续的业务代码即可,运行完了之后再次释放锁。

在这里插入图片描述

分布式锁的基本实现

接下来就是基于ZooKeeper,实现一下分布式锁。首先,定义了一个锁的接口Lock,很简单,仅仅两个抽象方法:一个加锁方法,一个解锁方法。Lock接口的代码如下:

package com.crazymakercircle.zk.distributedLock; /** * create by 尼恩 @ 疯狂创客圈 **/ public interface Lock { /** * 加锁方法 * * @return 是否成功加锁 */ boolean lock() throws Exception; /** * 解锁方法 * * @return 是否成功解锁 */ boolean unlock(); }

使用ZooKeeper实现分布式锁的算法,有以下几个要点:

(1)一把分布式锁通常使用一个Znode节点表示;如果锁对应的Znode节点不存在,首先创建Znode节点。这里假设为“/test/lock”,代表了一把需要创建的分布式锁。

(2)抢占锁的所有客户端,使用锁的Znode节点的子节点列表来表示;如果某个客户端需要占用锁,则在“/test/lock”下创建一个临时有序的子节点。

这里,所有临时有序子节点,尽量共用一个有意义的子节点前缀。

比如,如果子节点的前缀为“/test/lock/seq-”,则第一次抢锁对应的子节点为“/test/lock/seq-000000000”,第二次抢锁对应的子节点为“/test/lock/seq-000000001”,以此类推。

再比如,如果子节点前缀为“/test/lock/”,则第一次抢锁对应的子节点为“/test/lock/000000000”,第二次抢锁对应的子节点为“/test/lock/000000001”,以此类推,也非常直观。

(3)如果判定客户端是否占有锁呢?
很简单,客户端创建子节点后,需要进行判断:自己创建的子节点,是否为当前子节点列表中序号最小的子节点。如果是,则认为加锁成功;如果不是,则监听前一个Znode子节点变更消息,等待前一个节点释放锁。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwsydw.html