- 首页 > 生活 > >
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的日志所有此处并未截全,但是也能看到i是在按规律递减的,不会出现通过线程拿到相同值的情况
四、zk实现分布式锁的优缺点优点
- 集群部署不存在单点故障问题
- 统一视图zk集群每个节点对外提供的数据是一致的,数据一致性有所报障
- 临时有序节点zk提供临时有序节点,这样当客户端失去连接时会自动释放锁,不用像其他方案一样当拿到锁的实例服务不可用时,需要定时任务去删除锁;临时节点的特性就是当客户端失去连接会自动删除
- watch能力加持当获取不到锁时,无需客户端定期轮询争抢,只需watch前一节点即可,当有变化时会及时通知,比普通方案即及时又高效;注意这里最好只watch前一节点,如果watch整个父目录的话,当客户端并发较大时会不断有请求进出zk,给zk性能带来压力
经验总结扩展阅读
-
-
-
-
-
卡西欧手表哪一款性价比高,卡西欧系列的手表都有哪些好的推荐?
-
连衣裙 炎热的夏天,穿一件短款修身连衣裙游逛商厦绝对是最惬意的事情!
-
-
-
28岁女白领:靠出轨38岁领导走向事业顶峰,我却过得很煎熬
-
-
-
事业单位高温补贴多少钱 事业单位高温补贴发放是每年都有吗
-
-
-
-
-
-
-
-
久久说情感 凤凰男要求AA制,多年后却向妻子求助,妻子回应:我有钱,但不帮