springboot+zookeeper实现分布式锁的示例代码
作者:冬雪是你 发布时间:2022-02-05 08:48:48
标签:springboot,zookeeper,分布式锁
InterProcessMutex内部实现了zookeeper分布式锁的机制,所以接下来我们尝试使用这个工具来为我们的业务加上分布式锁处理的功能
zookeeper分布式锁的特点:1、分布式 2、公平锁 3、可重入
依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
<!-- zookeeper 客户端 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
<scope>provided</scope>
</dependency>
本地封装
这个工具类主要封装CuratorFramework这个client(连接Zookeeper)
@Slf4j
public class CuratorClientUtil {
private String zookeeperServer;
@Getter
private CuratorFramework client;
public CuratorClientUtil(String zookeeperServer) {
this.zookeeperServer = zookeeperServer;
}
// 创建CuratorFrameworkFactory并且启动
public void init() {
// 重试策略,等待1s,最大重试3次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
this.client = CuratorFrameworkFactory.builder()
.connectString(zookeeperServer)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
this.client.start();
}
// 容器关闭,CuratorFrameworkFactory关闭
public void destroy() {
try {
if (Objects.nonNull(getClient())) {
getClient().close();
}
} catch (Exception e) {
log.info("CuratorFramework close error=>{}", e.getMessage());
}
}
}
配置
@Configuration
public class CuratorConfigration {
@Value("${zookeeper.server}")
private String zookeeperServer;
// 注入时,指定initMethod和destroyMethod
@Bean(initMethod = "init", destroyMethod = "destroy")
public CuratorClientUtil curatorClientUtil() {
CuratorClientUtil clientUtil = new CuratorClientUtil(zookeeperServer);
return clientUtil;
}
}
测试代码
模拟不同客户端的请求
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
// 注入client工具类
@Autowired
private CuratorClientUtil curatorClientUtil;
// 在zookeeper的/rootLock节点下创建锁对应的临时有序节点
private String rootLock = "/rootLock";
@GetMapping("/testLock")
public Object testLock() throws Exception {
// 获取当前线程的名字,方便观察那些线程在获取锁
String threadName = Thread.currentThread().getName();
InterProcessMutex mutex = new InterProcessMutex(curatorClientUtil.getClient(), rootLock);
try {
log.info("{}---获取锁start", threadName);
// 尝试获取锁,最长等待3s,超时放弃获取
boolean lockFlag = mutex.acquire(3000, TimeUnit.SECONDS);
// 获取锁成功,进行业务处理
if (lockFlag) {
log.info("{}---获取锁success", threadName);
// 模拟业务处理,时间为3s
Thread.sleep(3000);
} else {
log.info("{}---获取锁fail", threadName);
}
} catch (Exception e) {
log.info("{}---获取锁异常", threadName);
} finally {
// 业务处理完成,释放锁,唤醒比当前线程创建的节点序号大(最靠近)的线程获取锁
mutex.release();
log.info("{}---锁release", threadName);
}
return "线程:" + threadName + "执行完成";
}
}
JMeter测试
我们使用JMeter模拟100个客户端同时并发的访问 localhost:8081/test/testLock,相当于100个客户端争抢分布式锁,结果如图右上角所示,100个请求花了5分6s,每个线程获取到锁后业务处理3s,100个线程理想时间为300s(Thread.sleep(3000)),所以运行时间符合。
zookeeper每个线程在/rooLock节点下创建的临时有序节点如下图,由于是临时的,所以线程释放锁后这些节点也会删除
100个线程程序日志打印
关于InterProcessMutex内部如何实现zookeeper分布式锁,请看我写的这篇文章:在这里
来源:https://blog.csdn.net/m0_45097637/article/details/123591560
0
投稿
猜你喜欢
- Kotlin中的面向对象面向对象面向对象的含义大家应该并不陌生,通过将事物抽象成对象,大大简化了程序的开发难度。我们常用的Java、Pyth
- 跨域的产生就是因为浏览器的同源策略。它是浏览器的核心安全功能,所谓的同源,就是指域名,协议,还有端口要相同。传统的方案就是JSONP(前端处
- Java 用反射设置对象的属性值实例详解/** * 用反射设置对象的属性值 * @param obj 需要設置值的對象 * @param f
- 一、环境说明集群环境至少需要3个节点(也就是3台服务器设备):1个Master,2个Slave,节点之间局域网连接,可以相互ping通,下面
- 1、Java主要特点简单性、跨平台性、分布性、安全性、健壮性、平 * 立与可移植性、多线程、动态性、面向对象的编程语言、支持垃圾自动收集处理等
- 方法的覆盖在类继承中,子类可以修改从父类继承来的方法,也就是说子类能创建一个与父类方法有不同功能的方法,但具有相同的名称、返回值类型、参数列
- 使用YZMHelper帮助类即可using System;using System.Web;using System.Drawing;usi
- 插入排序原理①把所有元素分成已排序和未排序两组②找到未排序组的第一个元素,向已经排序的组中进行插入③倒序遍历已经排好的元素,依次和待插入的元
- maven项目install时忽略执行test在项目所在文件夹根目录使用maven命令打包时<!-- 不执行单元测试,也不编译测试类
- 代理对象的生成方法是:Proxy.newProxyInstance(...) ,进入这个方法内部,一步一步往下走会发现会调用ProxyGen
- 本文详细的介绍了Spring组件的实现步骤,分享给大家,具体如下:背景Spring 框架提供了许多接口,可以使用这些接口来定制化 bean
- 前言前段时间因为工作的需要用到Spring事件,翻翻文档将功能实现了,但是存在少许理解不畅的地方,今天有空来梳理梳理。需求背景叶子同学在新入
- 1 配置文件的方法我们编写spring 框架的代码时候。一直遵循是这样一个规则:所有在spring中注入的bean 都建议定义成私有的域变量
- 枚举类型是一种的值类型,它用于声明一组命名的常数。(1)枚举的声明:枚举声明用于声明新的枚举类型。访问修辞符 enum 枚举名:基础类型&n
- jmap:Java内存映像工具jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文
- JDK * :利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。CGlib * :利用AS
- 最近有小伙伴问我,双枚举类该怎么写,还得包括根据key取值方法。于是就手写一个案例如下:/** * 关系类型枚举 */public enum
- 一、返回一般数据类型比如要根据 id 属性获得数据库中的某个字段值。mapper 接口:// 根据 id 获得数据库中的 username
- 最近项目进行适配的时候发现部分(如华为手机)存在底部虚拟按键的手机会因为虚拟按键的存在导致挡住部分界面,因为需要全屏显示,故调用虚拟按键隐藏
- OpenFeign介绍一开始,我们使用原生的 DiscoveryClient 发现服务和使用RestTemplate进行服务间调用,然后我们