当前位置:网站首页>使用zk实现分布式锁原理代码浅析
使用zk实现分布式锁原理代码浅析
2022-04-21 06:18:00 【原来你是小幸运】
- 主要原理:
创建一个带序号的临时node,并获取它,这里命名为nowNode
获取整个父node的所有子node
若是nowNode是子node的第一个,则认为它成功获取到锁
若不是第一个,证明在它前面有着别的线程注册了锁,所以开启监听它的上一个node
问:如何知道nowNode是第几个
带序号的字符串也是可以排序的,通过将获取到的子列表进行排序,即可知道是第几个
以下是实现的代码,主要用于帮助理解思想,课程在b站尚硅谷
import org.apache.zookeeper.*;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/** * @author lyb * @Date: 创建于 18:09 2021/9/26 * @说明: */
public class ZkLocks {
/** * zk客户端 */
private final ZooKeeper ZK;
/** * zk用户传进来的节点,使用写死的也可,主要是原理方面理解 */
private final String node;
/** * 上一个节点,主要用于监听,在函数回调时,释放await */
private String lastNode;
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private final CountDownLatch waitDownLatch = new CountDownLatch(1);
/** * 当前节点 */
private String nowNode;
public ZkLocks(String iP, String node) throws Exception {
ZK = new ZooKeeper(iP, 10000, new TestWatcher());
if (node.isEmpty()) {
node = "/";
} else if (!node.startsWith("/")) {
node = "/" + node;
}
this.node = node;
//等待zk连接成功
countDownLatch.await();
//判断zk路径是否存在
if (ZK.exists(node, false) == null) {
//不存在,则创建根节点
ZK.create(node, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
}
public void getLock() throws Exception {
//创建一个带序号的临时节点,序号是原子递增的,可以排序
nowNode = ZK.create(node + "/locks-", null,
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> childrenList = ZK.getChildren(node, false);
if (childrenList.size() == 1) return;
//先排序
Collections.sort(childrenList);
int index = childrenList.indexOf(nowNode.split("/")[2]);
if (index == -1) {
throw new Exception("节点出错");
}
//是第一个
if (index == 0) {
return;
}
//监听上一个节点的变化
lastNode = node + "/" + childrenList.get(index - 1);
ZK.getData(lastNode, true, null);
waitDownLatch.await();
}
void unLock() {
try {
ZK.delete(nowNode, -1);
} catch (InterruptedException | KeeperException e) {
e.printStackTrace();
}
}
class TestWatcher implements Watcher {
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
countDownLatch.countDown();
}
if (watchedEvent.getType() == Event.EventType.NodeDeleted &&
watchedEvent.getPath().equals(lastNode)) {
waitDownLatch.countDown();
}
}
}
}
测试类
/** * @author lyb * @Date: 创建于 19:07 2021/9/26 * @说明: */
public class ZkLockTest {
public static void main(String[] args) throws Exception {
final ZkLocks locks1 = new ZkLocks("127.0.0.1:2181", "/locksTest");
final ZkLocks locks2 = new ZkLocks("127.0.0.1:2181", "/locksTest");
System.out.println("连接完毕");
new Thread(() -> {
try {
locks1.getLock();
System.out.println("线程1获取到锁");
Thread.sleep(3000);
System.out.println("线程1释放锁");
locks1.unLock();
} catch (Exception e) {
}
}).start();
new Thread(() -> {
try {
locks2.getLock();
System.out.println("线程2获取到锁");
Thread.sleep(3000);
System.out.println("线程2释放锁");
locks2.unLock();
} catch (Exception e) {
}
}).start();
Thread.sleep(1000000000);
}
}
版权声明
本文为[原来你是小幸运]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_44741568/article/details/120547954
边栏推荐
猜你喜欢
随机推荐
SQL数据库语法学习笔记
imx6调试Lvds屏幕技术笔记
QT编程入门
Learn SCI paper drawing skills (b)
Tensorflow example 3: recognition training of verification code pictures. Each picture has 4 letters
电脑内网外网同时访问-解决办法
改图片后缀
applicationContext. How to solve the problem of XML becoming gray document
Qt 添加外部字库ttf
Sublime Text3 安装简体中文
【WPF】笔记
Launcher3 secondary development modification removes drawers, displays icons in workspace, deletes Google search box and other operations.
gojs 无水印版
将在CSDN中写好的文章导出为pdf格式
搭建自己的blog
2.bat脚本实例
【ThreadX】H743ZI+LAN8720+ThreadX+NetX Duo移植
【STM32&LWIP】记录一次诡异的ping不通的解决方法
每日网安认证测试题(2022年4月18日)
Draw biaxial separation diagram with ggplot2









