手写代码模拟zookeeper分布式锁

缓存架构SpringBoot集成Curator实现zookeeper分布式锁 一、分布式锁简介 1、什么是锁 在单机环境下,当存在多个线程可以同时改变某个共享变量时,就需要同步来实现该功能,使其线程安全。 而同步就是通过锁来实现的。锁保证了同一时刻只有一个线程来修改共享变量。 在单机环境下,Java提供了一些并发安全包可以一定程度上保证线程安全,但是在分布式环境(多机环境)下,这些并发包显得就无能为力了!! 2、什么是分布式 分布式的CAP理论: 任何一个分布式系统都无法... 阅读详情

1.zookeeper服务器

安装并准备zookeeper服务器

2.代码模拟分布式锁

2.1 maven工程

新建maven工程,导入zookeeper依赖

<dependency>
	<groupId>org.apache.zookeeper</groupId>
	<artifactId>zookeeper</artifactId>
	<version>3.4.13</version>
</dependency>

2.2 编写分布式锁实现类

  • 定义类成员变量
/**
 - 分布式锁,继承Lock接口,并实现
 - 
 - @author fenghe
 */
public class DistributedLock implements Lock {
	/**
	 * 保存一个zookeeper的实例,用于连接zookeeper
	 */
	private ZooKeeper zooKeeper;
	
	/**
	 * 默认根节点,持久化的节点
	 */
	private final String ROOT_LOCK_DIR = "/locks";
	
	/**
	 * 尝试获得锁时,新建的节点路径
	 */
	private String CURRENTLOCK = null;
	
	/**
	 * 未获得锁时,需要等待释放的节点路径
	 */
	private String WAITLOCK = null;
	
	/**
	 * 用于处理等待节点的通知
	 */
	private CountDownLatch latch;
}
  • 实现构造函数
/**
	 * 构造函数,传入zookeeper连接参数
	 * @param connectString
	 */
	public DistributedLock(String connectString) {
		final CountDownLatch countDownLatch = new CountDownLatch(1);
		try {
			//1.新建zookeeper连接
			zooKeeper = new ZooKeeper(connectString, 4000, new Watcher() {
				public void process(WatchedEvent event) {
					//2.连接成功后,唤醒countDownLatch
					if (KeeperState.SyncConnected.equals(event.getState())) {
						countDownLatch.countDown();
					}

				}
			});
			//3.等待连接成功后被唤醒
			countDownLatch.await();
			//4.判断ROOT_LOCK_DIR节点是否存在
			Stat stat = zooKeeper.exists(ROOT_LOCK_DIR, false);
			if (stat == null) {
				//5.如果不存在就新建持久化节点
				//PS:这里会有异步问题,最好保证这个节点在启动前已经创建,可以手动创建一个
				zooKeeper.create(ROOT_LOCK_DIR, "0".getBytes(), 
						ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
		}
	}
  • 实现tryLock()
	public boolean tryLock() {
		try {
			//1.创建一个临时有序节点
			CURRENTLOCK = zooKeeper.create(ROOT_LOCK_DIR+"/", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
			System.out.println(Thread.currentThread().getName()+" ==> " + CURRENTLOCK + " 尝试获得分布式锁...");
			//2.开始判断是否获得锁,即判断自己创建的节点序号是否最小
			List<String> nodes = zooKeeper.getChildren(ROOT_LOCK_DIR, false);
			SortedSet<String> set = new TreeSet<String>();
			nodes.forEach((node)->{
				set.add(ROOT_LOCK_DIR+"/"+node);
			});
			String first = set.first();
			//3.如果最小序号的节点就是自己创建的节点,则表示自己获得了锁
			if(CURRENTLOCK.equals(first)){
				return true;
			}
			//4.否则获得当前所有节点中序号比自己小的节点
			SortedSet<String> less = set.headSet(CURRENTLOCK);
			if(!less.isEmpty()){
				//5.获得所有比自己小的节点中最大的一个,设置为等待锁,即这个节点删除时,自己就可以获得锁
				WAITLOCK = less.last();
			}
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return false;
	}
  • 实现lock()
	public void lock() {
		//1.trylock返回true则表示获得锁
		if(this.tryLock()){
			System.out.println(Thread.currentThread().getName() + "==>" + CURRENTLOCK + " 获得锁...");
		}else{
			//2.反之则需要等待WAITLOCK节点释放
			try {
				//3.注册WAITLOCK的Watcher,当该节点删除时,唤醒latch
				Stat stat = zooKeeper.exists(WAITLOCK, new Watcher() {
					
					@Override
					public void process(WatchedEvent event) {
						if(latch!=null){
							latch.countDown();
						}
					}
				});
				if(stat!=null){
					System.out.println(Thread.currentThread().getName() + "==>等待锁==>" + WAITLOCK + " 释放...");
					//4. 等待WAITLOCK删除后被唤醒
					latch = new CountDownLatch(1);
					latch.await();
					//5. 唤醒即表示成功获得锁
					System.out.println(Thread.currentThread().getName() + "==>" + CURRENTLOCK + " 获得锁...");
				}
			} catch (KeeperException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
  • 实现unlock()
	public void unlock() {
		try {
			System.out.println(Thread.currentThread().getName()+" ==> " + CURRENTLOCK + " 释放锁...");
			//1.删除临时节点
			zooKeeper.delete(CURRENTLOCK, -1);
			CURRENTLOCK = null;
			//2.关闭连接
			zooKeeper.close();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (KeeperException e) {
			e.printStackTrace();
		}
	}

2.3 编写测试类

	public static void main(String[] args) throws IOException {
		CountDownLatch countDownLatch = new CountDownLatch(5);
		//1.模拟5个客户端通知竞争分布式锁
		for(int i=0;i<5;i++){
			new Thread(new Runnable() {
				public void run() {
					try {
						countDownLatch.await();
						DistributedLock distributedLock = new DistributedLock("127.0.0.1:2181");
						//2.新建分布式锁,并请求锁定
						distributedLock.lock();
						//3.模拟业务逻辑,在2秒内随机睡眠
						Thread.sleep(Math.round(2000));
						//4.释放锁
						distributedLock.unlock();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			},"Thread"+i).start();
			countDownLatch.countDown();
		}
		System.in.read();
	}

2.4 执行效果

2019-04-02 00:37:01,470 Thread1 ==> /locks/0000000000 尝试获得分布式锁...
2019-04-02 00:37:01,470 Thread0 ==> /locks/0000000002 尝试获得分布式锁...
2019-04-02 00:37:01,471 Thread2 ==> /locks/0000000003 尝试获得分布式锁...
2019-04-02 00:37:01,471 Thread3 ==> /locks/0000000001 尝试获得分布式锁...
2019-04-02 00:37:01,475 Thread1==>/locks/0000000000 获得锁...
2019-04-02 00:37:01,476 Thread4 ==> /locks/0000000004 尝试获得分布式锁...
2019-04-02 00:37:01,477 Thread0==>等待锁==>/locks/0000000001 释放...
2019-04-02 00:37:01,477 Thread3==>等待锁==>/locks/0000000000 释放...
2019-04-02 00:37:01,477 Thread2==>等待锁==>/locks/0000000002 释放...
2019-04-02 00:37:01,478 Thread4==>等待锁==>/locks/0000000003 释放...
2019-04-02 00:37:03,480 Thread1 ==> /locks/0000000000 释放锁...
2019-04-02 00:37:03,485 Thread3==>/locks/0000000001 获得锁...
2019-04-02 00:37:03,485 Session: 0x100002084d00074 closed
2019-04-02 00:37:03,487 EventThread shut down for session: 0x100002084d00074
2019-04-02 00:37:05,490 Thread3 ==> /locks/0000000001 释放锁...
2019-04-02 00:37:05,493 Thread0==>/locks/0000000002 获得锁...
2019-04-02 00:37:05,494 Session: 0x100002084d00072 closed
2019-04-02 00:37:05,494 EventThread shut down for session: 0x100002084d00072
2019-04-02 00:37:07,497 Thread0 ==> /locks/0000000002 释放锁...
2019-04-02 00:37:07,500 Thread2==>/locks/0000000003 获得锁...
2019-04-02 00:37:07,502 Session: 0x100002084d00070 closed
2019-04-02 00:37:07,502 EventThread shut down for session: 0x100002084d00070
2019-04-02 00:37:09,501 Thread2 ==> /locks/0000000003 释放锁...
2019-04-02 00:37:09,504 Thread4==>/locks/0000000004 获得锁...
2019-04-02 00:37:09,505 Session: 0x100002084d00073 closed
2019-04-02 00:37:09,505 EventThread shut down for session: 0x100002084d00073
2019-04-02 00:37:11,506 Thread4 ==> /locks/0000000004 释放锁...
2019-04-02 00:37:11,510 Session: 0x100002084d00071 closed
2019-04-02 00:37:11,510 EventThread shut down for session: 0x100002084d00071

可以看到第一次Thread1获得了锁,其临时节点为/locks/0000000000,而Thread3正在等待/locks/0000000000节点的释放;00:37:03时,Thread1释放了锁,即删除了/locks/0000000000节点,之后Thread3马上就获得了锁,以此类推,之后的线程也在前一个节点删除后,显示获得锁成功。

3.小结

通过代码模拟分布式锁的实现,帮助理解分布式锁的概念,及其设计思路。

  • 通过zookeeper临时有序节点的原理实现分布式锁
  • 根据节点序号判断是否获得锁
  • 利用watcher机制,链式监听前一个节点来感知是否删除,并确定自身锁的获得
  • 临时节点的特性能够保证获得锁的客户端即使异常中断,也不影响后续锁的获得
  • Curator封装了各种zookeeper的api,包括分布式锁的实现(上面的代码只是示意)
从“能跑”到“好用”:一名 Python 开发者的工程化进阶之路【Python心得篇】 Python 早已不只是写脚本、跑数据的工具。后端服务AI Agent 编排层自动化平台核心语言数据与业务之间的“中枢层”区别只在于:你是用脚本方式,还是工程方式在写。如果你已经能写“能跑的 Python”,下一步,就是让它长期可跑、稳定可演进。Python 的真正价值不在于“写得快”,而在于能否支撑持续演进的工程实践。当代码从一次性脚本走向长期运行的系统,开发者必须从结构设计、职责拆分、性能意识和类型约束等方面进行系统性思考。 阅读详情

相关推荐

DDR4技术原理详解

DDR4是DDR4-SDRAM的简写,即第4代DDR-SDRAM,DDR-SDRAM全称Double Date Rate Synchronous Dynamic Random Access Memory。本文重点解析DDR4技术规范及其背后的电子电路原理,以及编程使用DDR4过程中需要注意的性能事项。

ctbinzi的专栏 1万+

从零开始手写RPC框架(3)——ZooKeeper入门

ZooKeeper简介 ZooKeeper中的一些概念 ZooKeeper安装与常用命令 常用命令 ZooKeeper Java客户端 Curator入门

weixin_43739821的博客 1514

PRPD图谱分析从入门到精通:5种典型放电模式的识别手册

本文详细解析PRPD图谱分析技术,重点介绍电晕放电、悬浮放电等5种典型放电模式的识别方法。通过37组真实案例对比,提供关键识别区和诊断流程图模板,帮助工程师快速掌握变电站设备状态监测的核心技能,提升绝缘缺陷诊断准确率。

weixin_29214199的博客 473

Zookeeper之手写一个分布式锁

本篇最要是进一步加深学习ZK,算是一次简单的实践,巩固学习成果。

梁诗傑的博客 1187

【云原生】Docker可视化工具Portainer使用详解

Docker可视化工具Portainer使用详解

congge 1万+

iOS远程真机之WebDriverAgent 天坑记

一、WDA安装依赖报错:       这个东西神坑,我搞了一天都没找到解决方案,最后在appium讨论中发现,       解决方案是:       先定位到WebDriverAgent 所在路径$ cd /Users/XXXX/git/WebDriverAgent        然后运行:mkdir -p Resources/WebDriverAgent.bundle sh ./Scripts/b

甫式人生 7316

Zookeeper配置

简介ZK配置文件为conf/zoo.cfg基本配置 单机模式 配置项 功能 tickTime 这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。 dataDir Zookeeper保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。 clientPor

pjblogs的专栏 368

【GameFramework框架内置模块】6、实体(Entity)

实体Entity就是一个实体的基本单元,类似于Unity的GameObject对象本体,然后这个本体上面附加其他各种各样组件,才能实现各种各样的功能。一般需要在游戏运行时动态加载的游戏对象,比如怪物、武器、子弹、特效,都需要给这个物体挂载一个实体Entity,这样的话就可以方便的对实例出来的对象进行管理。下面就来看一下如何使用吧。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 3137

手写RPC框架--zookeeper为注册中心

上一次写了一个无注册中心的RPC,今天在前面的基础之上扩展为带注册中心的RPC框架。先把provider整体代码目录自定义一个注解Service,其中有参数interfa...

田维常 538

医疗影像分割 | 使用MedSAM训练自己的医学图像分割数据集

摘要 本文详细介绍了使用MedSAM模型训练自定义医学图像数据集的完整流程。主要内容包括:代码下载与环境配置(创建虚拟环境、安装依赖、验证CUDA)、数据集准备(目录结构、格式要求、命名规范及检查工具)、预训练模型下载(不同模型选择建议),以及训练脚本修改(解决文件名匹配、Windows系统NCCL支持、单GPU训练等常见问题)。通过逐步指导,帮助用户快速搭建MedSAM训练环境并适配自己的医学图像数据,实现高效的分割模型训练。

LiRongLu_的博客 489

基于 Qt 的轻量化工业组态软件设计与实现

本文设计并实现了一种基于Qt框架的轻量化工业组态软件,解决了传统组态软件体积庞大、部署复杂等问题。该软件采用模块化架构,集成可视化图形编辑、设备数据采集、脚本扩展等核心功能,具有跨平台运行、资源占用低、启动速度快等特点。通过关键技术优化,实现了高效稳定的数据采集、脚本控制和网络通信,可广泛应用于工业机器人HMI、小型PLC监控等轻量化场景。测试结果表明,该软件体积约30MB,运行内存占用60-80MB,启动时间1.2秒,满足工业轻量化监控需求。未来可扩展更多工业组件和协议支持,进一步提升应用价值。

谢谢大家的关注和点赞!这里只有纯纯的知识干货,没有一句废话。希望能实实在在帮到大家~要是觉得有用,别忘了给我点支持哟,你 142

手搓zookeeper样例实现记录

在学习zookeeper过程中,学习了一个监听节点状态变化,而开始、停止计数的案例。看懂了不代表就会了,于是想自己实现一个简单的版本。在自己实现的过程中也遇到了一些问题,在这里记录一下。

qq_16860161的博客 206

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

分布式锁实现方案-基于zookeeper的分布式锁实现(原理与代码)

分布式锁是一种用于控制分布式系统中对共享资源访问的同步机制,它确保在多个节点或进程中访问共享资源时的排他性。分布式锁的应用场景广泛,如防止多个用户同时修改数据、控制分布式系统中对共享资源的并发访问等。分布式锁的实现方式主要有三种,包括: 基于数据库的实现方式。基于缓存(如Redis或Memcached)的实现方式。基于ZooKeeper的实现方式等。在选择和使用分布式锁时,需要考虑到具体的业务需求、性能要求以及系统的可用性和可扩展性。今天我们就来看下如何基于Zookeeper实现分布式锁。

qq_25409421的博客 2842

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Zookeeper实现分布式锁及代码实例

Zookeeper实现分布式锁 文章目录Zookeeper实现分布式锁什么是锁分布式锁zk实现分布式锁zk实现分布式锁代码实现 什么是锁 在单机程序中,当存在多个线程可以同时改变某个变量(可变共享变量)时,为了保证线程安全(数据不能出现脏数据)就需要对变量或代码块做同步,使其在修改这种变量时能够串行执行消除并发修改变量。 对变量或者堆代码码块做同步本质上就是加锁。目的就是实现多个线程在一个时刻同一个代码块只能有一个线程可执行 分布式锁 分布式的环境中会不会出现脏数据的情况呢?类似单机程序中线程安全的问题

大数据开发、JAVA开发、人工智能AI 1579

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

zookeeper 实现分布式锁

本文介绍了基于 ZooKeeper 实现分布式锁的核心原理和具体实现,详细讲解了连接建立、加锁、解锁的实现过程,并提供完整Java代码示例

2301_76161469的博客 2718

ZooKeeper实现分布式锁

ZooKeeper实现分布式锁

weixin_46619605的博客 1149

基于zookeeper的分布式锁

一.分布式锁作用及其原理 1.为什么要有分布式锁 分布式服务中,如果各个服务节点需要去竞争资源,没办法使用单机多线程中JDK自带的锁,故此时需要分布式锁来协调。 2.企业中有哪些常见的手段来实现分布式锁 zookeeper、redis、memcache 3.分布式锁的原理 zookeeper:去创建相应的节点,创建成功,则表示获取到相应的锁,创建失败,则表示获取锁失败 ...

袖卷笛音的博客 2907

Zookeeper命令操作(初始Zookeeper、JavaAPI操作、分布式锁实现、模拟12306售票分布式锁、Zookeeper集群搭建、选举投票)

Zookeeper 是 Apache Hadoop 项目下的一个子项目,是一个树形目录服务Zookeeper 翻译过来就是 动物园管理员,他是用来管 Hadoop(大象)、Hive(蜜蜂)、Pig(小 猪)的管理员。简称zkZookeeper 是一个分布式的、开源的分布式应用程序的协调服务。Zookeeper 提供的主要功能包括:配置管理分布式锁集群管理ZooKeeper 是一个树形目录服务,其数据模型和Unix的文件系统目录树很类似,拥有一个层次化结构。这里面的每一个节点都被称为: ZNode,每个节点上

我要记录学习博客 858

zookeeper实现分布式锁

介绍了Zookeeper如何实现分布式锁,并使用代码进行了演示

凉茶铺的博客 6972

zookeeper Curator(4):分布式锁

摘要 分布式锁是解决分布式系统中跨JVM进程同步问题的关键技术。本文介绍了分布式锁的实现方式,包括基于缓存(如Redis)、Zookeeper和数据库(乐观锁、悲观锁)的方案。重点分析了Zookeeper分布式锁的原理,通过创建临时顺序节点和监听机制实现锁的获取与释放。此外,详细阐述了Curator提供的五种分布式锁API(如可重入锁、读写锁、信号量等)及其适用场景,并对比了各类锁的特性。最后以12306售票系统为例,演示了使用Curator的InterProcessMutex解决高并发下超卖问题的实践方案

不积跬步,无以至千里 1312

zookeeper分布式锁之InterProcessMutex

zookeeper分布式锁之InterProcessMutex zookeeper分布式锁原理 •核心思想:当客户端要获取锁,则创建节点,使用完锁,则删除该节点。 1.客户端获取锁时,在lock节点下创建临时顺序节点。 2.然后获取lock下面的所有子节点,客户端获取到所有的子节点之后,如果发现自己创建的子节点序号最小,那么就认为该客户端获取到了锁。使用完锁后,将该节点删除。 3.如果发现自己创建的节点并非lock所有子节点中最小的,说明自己还没有获取到锁,此时客户端需要找到比自己小的那个节点,同时对其注册

赵耀渊的博客 2226

Zookeeper 分布式锁实现原理

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。下面介绍 zookeeper 如何实现分布式锁,讲解排他锁和共享锁两类分布式锁。

1037

基于Zookeeper的分布式锁

01.分布式锁 1.1 为什么使用分布式锁 一个方法在高并发情况下的同一时间只能被同一个线程执行,在传统单体应用单机部署的情况下,可以使用Java并发处理相关的API(如ReentrantLcok或synchronized)进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题. 1.2 基于z

weixin_43525993的博客 580

Zookeeper-分布式锁

由于在多线程环境下上下文的切换,数据可能出现不一致的情况,我们需要保证数据安全,所以我们能想到的第一个就是加锁,所谓加锁是当一个线程访问某个数据时,进行限制,其他线程不能进行访问,直到该线程读取完,其他线程才可使用。 这里我们以 Redis 秒杀为例: 首先我们把库存预热到了Redis缓存中,库存为1。 A 服务去 Redis 查询库存发现为 1,说明商品存在,我去抢并且准备减 1 ,这时候库存还没有减。 这时 B 服务也去查询库存发现也是 1,这时 B 服务也抢到了,那也减 1。 C 服务同上。 等所有

养歌的博客 1647

基于Zookeeper实现分布式锁

收到

weixin_43949634的博客 1033

使用zookeeper实现分布式锁

在zookeeper中,根据zookeeper的特性,我们有两种方式来实现分布式锁。 实现方式一: 在zookeeper节点下面,让需要获得锁的程序,都去创建名为Lock的临时节点,因为多实例创建的节点名称相同,只会有一个实例创建节点成功,那么这个实例就可以获得锁,就可以去执行本身代码逻辑,其他没有创建成功的实例,就去注册一个watch去监听Lock节点,当抢到锁的实例执行完本身程序后,就会去...

huxiaodong1994的博客 1675
上一篇: zookeeper的使用及基本概念
下一篇: Jenkins从零开始
封何
博客等级 码龄14年 13粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值