- 首页 > 生活百科 > >
zk系列三:zookeeper实战之分布式锁实现( 二 )
提示:代码中注释的代码块可以关注下,原本是直接阻塞式编程,将获取所有子节点并释放锁的操作直接写在getChildren方法的回调里,后来发现当节点被删除时我们还要重新抢锁,那么代码就冗余了,于是结合响应式编程的思想,将这段核心代码放到getChildren方法的回调
里 , 这样代码简洁了并且可以让业务更只关注于getChildren
这件事了
2、测试代码编写线程安全问题复现
package com.darling.service.zookeeper.lock;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.junit.Test;/** * @description:开启是个线程给i做递减操作,未加锁的情况下会有线程安全问题 * @author: dll * @date: Created in 2022/11/8 8:32 * @version: * @modified By: */@Slf4jpublic class ZkLockTest02 {private int i = 10;@Testpublic void test() throws InterruptedException {for (int n = 0; n < 10; n++) {new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {Thread.sleep(100);incre();}}).start();}Thread.sleep(5000);log.info("i = {}",i);}/*** i递减 线程不安全*/public void incre(){//i.incrementAndGet();log.info("当前线程:{},i = {}",Thread.currentThread().getName(),i--);}}
- 上面代码运行结果如下:
文章插图
使用上面封装的
ZkLockHelper
实现的分布式锁
package com.darling.service.zookeeper.lock;import lombok.SneakyThrows;import lombok.extern.slf4j.Slf4j;import org.apache.zookeeper.ZooKeeper;import org.junit.After;import org.junit.Before;import org.junit.Test;/** * @description: 使用zk实现的分布式锁解决线程安全问题 * @author: dll * @date: Created in 2022/11/8 8:32 * @version: * @modified By: */@Slf4jpublic class ZkLockTest03 {ZooKeeper zkClient;@Beforepublic void conn (){zkClient= ZkUtil.getZkClient();}@Afterpublic void close (){try {zkClient.close();} catch (InterruptedException e) {e.printStackTrace();}}private int i = 10;@Testpublic void test() throws InterruptedException {for (int n = 0; n < 10; n++) {new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {Thread.sleep(100);ZkLockHelper zkHelper = new ZkLockHelper();// 这里给zkHelper设置threadName是为了后续调试的时候日志打?。阌诠鄄齑嬖诘奈侍?String threadName = Thread.currentThread().getName();zkHelper.setThreadName(threadName);zkHelper.setZkClient(zkClient);// tryLock上锁zkHelper.tryLock();incre();log.info("线程{}正在执行业务代码...",threadName);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 释放锁zkHelper.unLock();}}).start();}while (true) {}}/*** i递减 线程不安全*/public void incre(){//i.incrementAndGet();log.info("☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆当前线程:{},i = {}",Thread.currentThread().getName(),i--);}}
- 运行结果如下:
文章插图
【zk系列三:zookeeper实战之分布式锁实现】由于日志中掺杂着zk的日志所有此处并未截全,但是也能看到i是在按规律递减的,不会出现通过线程拿到相同值的情况
四、zk实现分布式锁的优缺点优点
- 集群部署不存在单点故障问题
- 统一视图zk集群每个节点对外提供的数据是一致的,数据一致性有所报障
- 临时有序节点zk提供临时有序节点,这样当客户端失去连接时会自动释放锁,不用像其他方案一样当拿到锁的实例服务不可用时,需要定时任务去删除锁;临时节点的特性就是当客户端失去连接会自动删除
- watch能力加持当获取不到锁时,无需客户端定期轮询争抢,只需watch前一节点即可 , 当有变化时会及时通知,比普通方案即及时又高效;注意这里最好只watch前一节点,如果watch整个父目录的话,当客户端并发较大时会不断有请求进出zk,给zk性能带来压力
缺点
- 与单机版redis比较的话性能肯定较差,但是当客户端集群足够庞大且业务量足够多时肯定还是集群更加稳定
好了,zk实现分布式锁的编码实现就到这了 , 后续有时间再写偏redis的,其实思路缕清了,编码实现还是很简单的
推荐阅读
-
-
-
父母买房可以写未成年孩子的名字吗,规避转让税但不能贷款
-
-
-
-
-
-
-
-
熟黄芪泡水喝的功效与作用 熟黄芪泡水喝有哪些功效与作用
-
-
-
今年广东调整养老金的新消息 2022广东省养老金上调方案及补发时间
-
昆明机场离哪个高铁站近,昆明飞机场到高铁站有多远?
-
-
-
-
-