Apache Curator 分布式锁的介绍,以及案例
可重入锁(InterProcessMutex):这种锁允许同一个客户端多次获取同一把锁而不会被阻塞,类似于Java中的ReentrantLock
。它通过在Zookeeper的指定路径下创建临时序列节点来实现锁的功能。如果获取锁失败,当前线程会监听前一个节点的变动情况并等待,直到被唤醒或超时
package com.zz.lock;import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;public class CuratorReentrantLockExample {private final String lockPath = "/curator/lock"; // 锁的Zookeeper路径private CuratorFramework client; // Curator客户端private InterProcessMutex mutex; // 可重入锁// 初始化Curator客户端和可重入锁public void init() {// 设置Zookeeper服务地址String connectString = "192.168.200.130:2181";// 设置重试策略ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 3);// 创建Curator客户端client = CuratorFrameworkFactory.newClient(connectString, retryPolicy);client.start();// 创建可重入锁mutex = new InterProcessMutex(client, lockPath);}// 执行业务逻辑,使用可重入锁public void executeBusinessLogic() {try {// 获取锁mutex.acquire();// 模拟业务逻辑System.out.println("当前线程获得锁,开始执行业务逻辑。");// 模拟重入逻辑reentrantLock();// 模拟业务逻辑System.out.println("当前线程完成业务逻辑执行。");} catch (Exception e) {e.printStackTrace();} finally {// 确保释放锁if (mutex.isAcquiredInThisProcess()) {try {mutex.release();} catch (Exception e) {e.printStackTrace();}}}}// 模拟可重入逻辑public void reentrantLock() {try {// 再次获取同一把锁mutex.acquire();System.out.println("当前线程重入成功,再次获得同一把锁。");// 模拟一些操作...} catch (Exception e) {e.printStackTrace();} finally {// 释放锁if (mutex.isAcquiredInThisProcess()) {try {mutex.release();} catch (Exception e) {e.printStackTrace();}}}}// 程序入口public static void main(String[] args) {CuratorReentrantLockExample example = new CuratorReentrantLockExample();example.init();// 执行业务逻辑example.executeBusinessLogic();}
}
不可重入锁(InterProcessSemaphoreMutex):与可重入锁类似,但不允许同一个线程在持有锁的情况下再次获取该锁。这种锁很容易导致死锁,使用时需要特别注意
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;public class CuratorReentrantLockExample {private final String lockPath = "/curator/lock"; // 锁的Zookeeper路径private CuratorFramework client; // Curator客户端private InterProcessMutex mutex; // 可重入锁// 初始化Curator客户端和可重入锁public void init() {// 设置Zookeeper服务地址String connectString = "127.0.0.1:2181";// 设置重试策略ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 3);// 创建Curator客户端client = CuratorFrameworkFactory.newClient(connectString, retryPolicy);client.start();// 创建可重入锁mutex = new InterProcessMutex(client, lockPath);}// 执行业务逻辑,使用可重入锁public void executeBusinessLogic() {try {// 获取锁mutex.acquire();// 模拟业务逻辑System.out.println("当前线程获得锁,开始执行业务逻辑。");// 模拟重入逻辑reentrantLock();// 模拟业务逻辑System.out.println("当前线程完成业务逻辑执行。");} catch (Exception e) {e.printStackTrace();} finally {// 确保释放锁if (mutex.isAcquiredInThisProcess()) {try {mutex.release();} catch (Exception e) {e.printStackTrace();}}}}// 模拟可重入逻辑public void reentrantLock() {try {// 再次获取同一把锁mutex.acquire();System.out.println("当前线程重入成功,再次获得同一把锁。");// 模拟一些操作...} catch (Exception e) {e.printStackTrace();} finally {// 释放锁if (mutex.isAcquiredInThisProcess()) {try {mutex.release();} catch (Exception e) {e.printStackTrace();}}}}// 程序入口public static void main(String[] args) {CuratorReentrantLockExample example = new CuratorReentrantLockExample();example.init();// 执行业务逻辑example.executeBusinessLogic();}
}
读写锁(InterProcessReadWriteLock):提供一对相关的锁,读锁可以被多个读操作共享,而写锁则独占。一个拥有写锁的线程可以获取读锁,但读锁不能升级为写锁。这种锁是公平的,保证用户按请求顺序获取锁。(读写锁在逻辑上有点像数据库的事务)
package com.zz.lock;import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;public class CuratorReadWriteLockExample {private final String lockPath = "/curator/read-write-lock"; // 锁的Zookeeper路径private CuratorFramework client; // Curator客户端private InterProcessReadWriteLock lock; // 读写锁// 初始化Curator客户端和读写锁public void init() {// 设置Zookeeper服务地址String connectString = "192.168.200.130:2181";// 设置重试策略ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 3);// 创建Curator客户端client = CuratorFrameworkFactory.newClient(connectString, retryPolicy);client.start();// 创建读写锁lock = new InterProcessReadWriteLock(client, lockPath);}// 执行读操作public void executeReadOperation() throws Exception {try {// 获取读锁lock.readLock().acquire();// 模拟读操作System.out.println("读操作开始,线程安全地读取数据。");// 模拟读操作延迟Thread.sleep(3000);System.out.println("读操作结束。");} catch (Exception e) {e.printStackTrace();} finally {// 释放读锁if (lock.readLock().isAcquiredInThisProcess()) {lock.readLock().release();}}}// 执行写操作public void executeWriteOperation() throws Exception {try {// 获取写锁lock.writeLock().acquire();// 模拟写操作System.out.println("写操作开始,线程独占资源进行写入。");// 模拟写操作延迟Thread.sleep(3000);System.out.println("写操作结束,更新了数据。");} catch (Exception e) {e.printStackTrace();} finally {// 释放写锁if (lock.writeLock().isAcquiredInThisProcess()) {lock.writeLock().release();}}}// 程序入口public static void main(String[] args) {CuratorReadWriteLockExample example = new CuratorReadWriteLockExample();example.init();// 启动多个读操作线程for (int i = 0; i < 5; i++) {new Thread(() -> {try {example.executeReadOperation();} catch (Exception e) {e.printStackTrace();}}).start();}// 启动写操作线程new Thread(() -> {try {example.executeWriteOperation();} catch (Exception e) {e.printStackTrace();}}).start();}
}
联锁(InterProcessMultiLock):这是一个锁的容器,可以同时获取多个锁。如果获取过程中任何一个锁请求失败,已获取的所有锁都会被释放。这在需要同时持有多个锁执行操作的场景中非常有用
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.framework.recipes.locks.InterProcessLock;
import org.apache.curator.framework.recipes.locks.InterProcessMultiLock;
import java.util.Arrays;
import java.util.List;public class InterProcessMultiLockExample {private CuratorFramework client;private List<String> lockPaths = Arrays.asList("/lock1", "/lock2", "/lock3");private List<InterProcessLock> locks = lockPaths.stream().map(path -> new InterProcessMutex(client, path)).collect(Collectors.toList());private InterProcessMultiLock multiLock;public void init() {String connectString = "127.0.0.1:2181";RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 3);client = CuratorFrameworkFactory.newClient(connectString, retryPolicy);client.start();multiLock = new InterProcessMultiLock(locks);}public void executeProtectedOperation() {try {multiLock.acquire();// 所有锁都已获取,执行你的业务逻辑System.out.println("All locks acquired, performing business logic.");// 业务逻辑...} catch (Exception e) {e.printStackTrace();} finally {// 确保释放所有锁multiLock.release();}}public static void main(String[] args) {InterProcessMultiLockExample example = new InterProcessMultiLockExample();example.init();example.executeProtectedOperation();}
}
信号量(InterProcessSemaphoreV2):Curator提供了一种信号量实现,可以控制同时访问某个资源的线程数量。通过acquire
方法请求获取信号量,使用完成后通过returnAll
方法释放
信号量(Semaphore)确实可以起到限流的作用。在分布式系统中,信号量是一种常用的限流工具,它通过控制同时访问某个资源或执行某个操作的线程数量来实现限流。以下是信号量实现限流的几个关键点:1. **资源限制**:信号量通过一个计数器来限制可用资源的数量。例如,如果你有10个停车位,你可以设置信号量的初始值为10。2. **请求处理**:当一个线程需要访问资源时,它首先尝试从信号量中获取一个“许可”(lease)。如果信号量的计数器大于0,该线程成功获取一个许可,然后继续执行。否则,线程将被阻塞,直到其他线程释放资源。3. **释放资源**:线程完成资源访问后,必须释放它获取的许可,通过将许可返还给信号量来实现。这会将信号量的计数器增加1,允许其他等待的线程获取许可。4. **公平性**:信号量通常是公平的,意味着线程将按照它们请求许可的顺序来获得它们。这有助于避免某些线程长时间等待访问资源。5. **跨JVM共享**:在分布式系统中,不同的进程可能在不同的JVM中运行。Apache Curator 提供的 `InterProcessSemaphoreV2` 允许跨JVM共享信号量状态,因此所有相关进程都能协调地访问共享资源。6. **自动资源回收**:如果持有信号量许可的线程或进程崩溃,Curator 会自动释放该许可,确保资源不会被永久占用,其他线程可以继续获取该资源。通过这种方式,信号量可以有效地控制对共享资源的并发访问,防止系统过载,从而实现限流。这在许多场景下都非常有用,比如数据库连接池、线程池、外部服务调用等。
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreV2;
import org.apache.curator.framework.recipes.locks.Lease;
import org.apache.curator.retry.ExponentialBackoffRetry;public class InterProcessSemaphoreV2Demo {private static final String PATH = "/semaphore/path";private static CuratorFramework client;public static void main(String[] args) throws Exception {// 初始化Curator客户端client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(3000, 2));client.start();// 创建InterProcessSemaphoreV2实例,设置最大租约数为5InterProcessSemaphoreV2 semaphore = new InterProcessSemaphoreV2(client, PATH, 5);// 线程示例,模拟同时请求信号量的多个线程for (int i = 0; i < 10; i++) {new Thread(new SemaphoreTask(semaphore)).start();}// 等待一段时间,让线程执行Thread.sleep(10000);// 关闭客户端连接client.close();}static class SemaphoreTask implements Runnable {private final InterProcessSemaphoreV2 semaphore;public SemaphoreTask(InterProcessSemaphoreV2 semaphore) {this.semaphore = semaphore;}@Overridepublic void run() {try {Lease lease = semaphore.acquire();System.out.println(Thread.currentThread().getName() + " acquired a lease.");// 模拟业务逻辑处理Thread.sleep(3000);// 释放信号量租约semaphore.returnLease(lease);System.out.println(Thread.currentThread().getName() + " returned a lease.");} catch (Exception e) {e.printStackTrace();}}}
}
分布式锁的实现原理:Curator的分布式锁通常是基于Zookeeper的临时顺序节点来实现的。当多个客户端尝试获取锁时,Zookeeper会为它们创建顺序节点,并让它们按照节点的序号依次尝试获取锁。未获取到锁的客户端会监听前一个序号的节点,一旦前一个节点释放锁,监听的客户端就会尝试获取锁
相关文章:
Apache Curator 分布式锁的介绍,以及案例
可重入锁(InterProcessMutex):这种锁允许同一个客户端多次获取同一把锁而不会被阻塞,类似于Java中的ReentrantLock。它通过在Zookeeper的指定路径下创建临时序列节点来实现锁的功能。如果获取锁失败,当前线程会监听前一…...

自动化测试 — selenium + Java
什么是自动化测试 将人为驱动的测试行为转化为机器执行的过程。 自动化测试包括UI 自动化,接口自动化,单元测试自动化。按照这个金字塔模型来进行自动化测试规划,可以产生最佳的自贡话测试产出投入比(ROI ),…...

【SpringBoot系列】接口参数的默认值与必要性
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
茶余饭后(五)
真正出类拔萃的人 往往都是狠角色, 他们具备着一种独特的特质 那就是: 目标清晰 意志如铁 底线分明 同时手段又极为高明 且勤奋不屑 在处于劣势时 他们表现的极为谦逊和低调 像一只温顺无害的小羊羔 然而一旦时机成熟 他们便会毫不犹豫的展现出强…...

【网络编程详解】
🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 🔥…...

C# winform三层架构 实现增删改查( 显示数据,查询数据 显示,查询篇)
一.留言 上一篇讲解了如何去添加数据,那么本章节我们来做,添加数据后显示,以及咋现有的数据里,查询我们所需要的数据。 二.显示 首先我们看上一篇更新,我们在添加成功后跳转页面显示数据,那么跳转代码只…...
Apache Kylin 系列入门教程
Apache Kylin 是一款开源的分布式分析引擎,主要用于提供SQL接口及多维分析(OLAP)能力以支持超大规模数据集。它能在亚秒级时间内完成PB级别的数据查询。本文将带你一步步了解如何安装、配置和使用Apache Kylin来构建数据仓库,并执…...
如何识别并防御漏洞扫描类攻击
随着网络安全威胁的不断演变,漏洞扫描已成为黑客常用的手段之一,旨在发现目标系统中的弱点以便进行后续攻击。高防服务作为一种专业的安全防护措施,能够在一定程度上识别并阻止这类攻击行为。本文将深入探讨高防服务是如何识别并防御漏洞扫描…...

冷思考:低代码的AI Agent构建平台能创造价值吗?
当前AI 圈中热点讨论的产品,除了以ChatGPT为代表的Chatbot领域,以及以Character.ai 为代表的AI虚拟社交领域,另一个热度较高的领域就是AI Agent领域。 大模型发展到今天,已经基本达成了一个共识:错综复杂的工作任务无…...
Spring Boot如何自定义注解?
1.什么是注解 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元…...
gin框架传入的gin.context参数是池化的
1. gin.context参数不但是池化的,而且是指针 2. 但是gin.context又实现了context的接口。因此,可以当作context去使用 3. 这就会导致一个很严重的问题: 1. 池化导致了复用后的ctx将会将之前使用的ctx中的内容进行覆盖。 2. 实现了context接…...

AWS注册是否必须使用美元银行卡
亚马逊网络服务(AWS)作为全球领先的云计算平台,吸引了众多企业和个人用户。然而,不少人在注册AWS账户时会产生疑问:是否必须使用美元银行卡?实际上,这种说法并不准确。虽然AWS的主要结算货币是美元,但用户在注册和使用过程中有多种支付方式可供选择。我们结合九河云的分析来告…...

Spring IOC 注入的3种方式
Spring IOC 注入的3种方式 1. 构造器注入(Constructor Injection)2. Setter方法注入(Setter Injection)3. 字段注入(Field Injection) 💖The Begin💖点点关注,收藏不迷路…...

无人机影像基于机器学习的遥感反演及其结果可视化,定量遥感反演结果出图,相关性分析,指标筛选,特征选择
无人机影像或者卫星遥感反演分类模型的建立,反演模型的可视化制图出图,相关性分析,指标筛选,特征选择。代码太多,可企鹅联系: 指标的相关性分析。572 特征选择,贡献性最大的特征。412 LAI反演&…...

Eclipse插件之Java Dependency Viewer(显示类和包的关系图)
Java Dependency Viewer 插件的作用 Eclipse插件Java Dependency Viewer是一个为Java项目提供依赖关系可视化功能的工具。 在复杂的Java项目中,理解和分析类与类之间、包与包之间的依赖关系是非常有用的。Java Dependency Viewer插件通过生成依赖关系图,…...
H5小游戏出海,如何流量变现?
根据数据显示, 90%的轻度休闲游戏收入来自广告,即IAA(In-App Advertising)。使用这种形式进行变现的游戏类型大多以超休闲游戏为主,玩法简单、游戏内容轻度、风格简洁、游戏时间碎片化且即时娱乐性较高,收益…...

轻空间六大专利优势:引领气膜建筑新时代
在绿色建筑和科技创新的驱动下,轻空间不断突破传统建筑的限制,推出了一系列具有前瞻性和高性能的专利技术。通过这些技术,轻空间不仅为建筑行业注入了新动力,也为未来的气膜建筑设定了更高的标准。 低碳建材:“clearsk…...
LeetCode-day37-2940. 找到 Alice 和 Bob 可以相遇的建筑
LeetCode-day37-2940. 找到 Alice 和 Bob 可以相遇的建筑 题目描述示例示例1:示例2: 思路代码 题目描述 给你一个下标从 0 开始的正整数数组 heights ,其中 heights[i] 表示第 i 栋建筑的高度。 如果一个人在建筑 i ,且存在 i &…...
unity 判断平台
原文链接 Unity中判断平台的方法 Unity提供了一些方法来判断当前运行的平台,其中包括了判断是否为i0S平台。以下是几种常用的方法1.Application.platform Applicaion,platom 是Unity中的一个枚举类型,用于表示当前运行的平台。可以通过比较 Apication,p…...

PyCharm找不到Python了咋办
Python发生了重装的,且新的路径和原有路径不同,就会出现如下的错误: 解决办法: 点开PyCharm菜单的File/Setting 然后: 有上图的提示,说明需要将原来的venv进行清空。 如此操作之后,原来的红色…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...