赞
踩
org.springframework.boot
2.0.5.RELEASE
org.springframework.boot
2.0.5.RELEASE
org.apache.zookeeper
zookeeper
3.4.9
org.projectlombok
lombok
1.18.12
provided
junit
junit
/**======================================================================================
方法描述:zookeeper分布式锁
逻辑步骤:
实现 AutoCloseable 可自动关闭资源
Watcher观察器
======================================================================================*/
//zookeeper分布式锁
//实现 AutoCloseable 可自动关闭资源
//Watcher观察器
@Slf4j
public class ZookeeperLock implements AutoCloseable, Watcher {
//zookeeper客户端对象
private ZooKeeper zooKeeper;
//当前节点
private String currentNode;
//通过构造器初始化zookeeper
ZookeeperLock(){
try {
//参数:链接字符串 , 会话超时 , 监听器
this.zooKeeper = new ZooKeeper(“172.16.2.54:2181”,10000,this);
} catch (IOException e) {
e.printStackTrace();
}
}
/**======================================================================================
方法描述:提供获取锁的方法: code作为业务相关的编码,比如传入订单ID,就锁住这个订单
逻辑步骤:
1.创建根节点
2.进来一个线程,就为线程在zookeeper的根节点创建一个瞬时有序节点
======================================================================================*/
public boolean getLock(String code){
try {
//1.创建根节点,如果不存在,stat为null 就创建
String path = “/” + code;
Stat exists = zooKeeper.exists(path, false);
//创建节点
if(null == exists){
// 节点路径 ,节点值 ,权限:不需要账户密码就能链接 , 创建模式:顺序临时节点
zooKeeper.create(path,code.getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
//2.进来一个线程,就为线程在zookeeper创建一个瞬时有序节点 , 如: /xx/xx000000001 ;/xx/xx000000002
//把当前节点保存为成员变量,后面用来做判断
currentNode = zooKeeper.create(path+path,code.getBytes() , ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
//3.对所有的子节点进行排序
List children = zooKeeper.getChildren(path, false);
Collections.sort(children);
//4.如果排序过的children中的第一个和 currentNode 一致,拿到锁
String firstNode = children.get(0);
if(currentNode.endsWith(firstNode)){
return true;
}
//5.如果不是第一个节点,需要监听前一个节点
//用一个临时变量记录当前节点的上一个节点
String previousNode = firstNode;
for(String node : children){
if(currentNode.endsWith(node)){
//如果当前节点是node节点 ,那么就监听它的上一个节点 :比如 currentNode 这里是 0003节点 ,那 node就是 0002节点
//第一个参数是监听的节点,第二个参数是是否要监听,zooKeeper在初始化的时候设置好了监听器
log.info(“监听上一个节点:{}”,node);
zooKeeper.exists(path+“/”+previousNode,true);
}else{
//把children中的节点复制给上一个节点
previousNode = node;
}
}
//代码到这里,节点已经做好监听了,只需要等待,等待上一个节点完成工作后唤醒他
synchronized (this){
//wait会释放锁
wait();
}
//到这里说明被唤醒,说明获取到锁
log.info(“拿到锁:{}”,currentNode);
return true;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
@Override
public void close() {
//释放锁 :节点路径, 节点版本号(-1匹配所有版本)
log.info(“释放节点:{}”,currentNode);
if(null != currentNode){
try {
zooKeeper.delete(currentNode ,-1);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
}
}
@Override
public void process(WatchedEvent watchedEvent) {
//当节点被释放,就会到这里被监听到
if(watchedEvent.getType() == Event.EventType.NodeDeleted){
synchronized (this){
//唤醒等待的线程
log.info(“当前节点:{},唤醒”,watchedEvent.getPath());
notify();
}
}
}
}
public class ZKTest {
@Test
public void testZK() throws Exception {
for(int i = 0 ; i < 10 ; i++){
new Thread(()->{
ZookeeperLock zookeeperLock = new ZookeeperLock();
boolean getLock = zookeeperLock.getLock(“order”);
System.out.println(“是否获取到锁:”+getLock);
zookeeperLock.close();
}).start();
}
Thread.sleep(5000);
}
}
打印日志:
09:18:24.500 [Thread-0] INFO cn.itsource.ZookeeperLock - /order/order0000000014监听上一个节点:/order/order0000000013
09:18:24.500 [Thread-9] INFO cn.itsource.ZookeeperLock - /order/order0000000017监听上一个节点:/order/order0000000016
09:18:24.500 [Thread-1] INFO cn.itsource.ZookeeperLock - /order/order0000000019监听上一个节点:/order/order0000000018
09:18:24.500 [Thread-8] INFO cn.itsource.ZookeeperLock - /order/order0000000018监听上一个节点:/order/order0000000017
09:18:24.500 [Thread-4] INFO cn.itsource.ZookeeperLock - /order/order0000000016监听上一个节点:/order/order0000000015
09:18:24.500 [Thread-2] INFO cn.itsource.ZookeeperLock - /order/order0000000020监听上一个节点:/order/order0000000019
09:18:24.500 [Thread-3] INFO cn.itsource.ZookeeperLock - /order/order0000000013监听上一个节点:/order/order0000000012
09:18:24.500 [Thread-7] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000011
09:18:24.500 [Thread-6] INFO cn.itsource.ZookeeperLock - /order/order0000000015监听上一个节点:/order/order0000000014
09:18:24.500 [Thread-5] INFO cn.itsource.ZookeeperLock - /order/order0000000012监听上一个节点:/order/order0000000011
09:18:24.509 [Thread-5-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000011,唤醒
09:18:24.509 [Thread-5] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000012
是否获取到锁:true
09:18:24.509 [Thread-5] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000012
09:18:24.511 [Thread-3-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000012,唤醒
09:18:24.512 [Thread-3] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000013
是否获取到锁:true
09:18:24.512 [Thread-3] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000013
09:18:24.514 [Thread-0-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000013,唤醒
09:18:24.515 [Thread-0] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000014
是否获取到锁:true
09:18:24.515 [Thread-0] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000014
09:18:24.517 [Thread-6-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000014,唤醒
09:18:24.517 [Thread-6] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000015
是否获取到锁:true
09:18:24.517 [Thread-6] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000015
09:18:24.520 [Thread-4-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000015,唤醒
09:18:24.520 [Thread-4] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000016
是否获取到锁:true
09:18:24.520 [Thread-4] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000016
09:18:24.522 [Thread-9] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000017
是否获取到锁:true
09:18:24.522 [Thread-9] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000017
09:18:24.525 [Thread-8-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000017,唤醒
09:18:24.525 [Thread-8] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000018
是否获取到锁:true
09:18:24.525 [Thread-8] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000018
09:18:24.527 [Thread-1-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000018,唤醒
09:18:24.527 [Thread-1] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000019
是否获取到锁:true
09:18:24.527 [Thread-1] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000019
09:18:24.530 [Thread-2-EventThread] INFO cn.itsource.ZookeeperLock - 当前节点:/order/order0000000019,唤醒
09:18:24.530 [Thread-2] INFO cn.itsource.ZookeeperLock - 拿到锁:/order/order0000000020
是否获取到锁:true
09:18:24.530 [Thread-2] INFO cn.itsource.ZookeeperLock - 释放节点:/order/order0000000020
这个效果看起来是对的。但是如果自己基于zookeeper封装分布式锁未免太过麻烦,而且容易出BUG,Apache提供了一个基于Zookeeper的客户端工具curator已经实现了分布式锁的封装,我们使用它就可以了。
Apache Curator是用于Apache ZooKeeper(一种分布式协调服务)的Java / JVM客户端库。它包括一个高级API框架和实用程序,使使用Apache ZooKeeper变得更加轻松和可靠。解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等等。
重点是它对分布式锁进行了封装 :http://curator.apache.org/getting-started.html
org.apache.curator
curator-recipes
4.1.0
//初始化方法start
@Bean(initMethod = “start”,destroyMethod = “close”)
public CuratorFramework curatorFramework(){
//重试策略
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
//创建客户端
CuratorFramework client = CuratorFrameworkFactory.newClient(“172.16.2.54:2181”, retryPolicy);
return client;
}
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppStart.class)
public class ZKTest {
@Autowired
private CuratorFramework curatorFramework;
/**======================================================================================
======================================================================================*/
@Test
public void testCurator() throws Exception {
for(int i = 0 ; i < 10 ; i++){
new Thread(()->{
testCuratorLock();
}).start();
}
Thread.sleep(5000);
}
public void testCuratorLock(){
//分布式锁
InterProcessMutex lock = new InterProcessMutex(curatorFramework, “/order”);
try {
if ( lock.acquire(1, TimeUnit.SECONDS) ){
//处理业务逻辑
log.info(“获取到锁”);
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
//释放锁
log.info(“释放锁”);
lock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
打印效果
2021-05-15 09:54:32.251 INFO 22488 — [ Thread-4] cn.itsource.ZKTest : 获取到锁
2021-05-15 09:54:32.252 INFO 22488 — [ Thread-4] cn.itsource.ZKTest : 释放锁
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
即使是面试跳槽,那也是一个学习的过程。只有全面的复习,才能让我们更好的充实自己,武装自己,为自己的面试之路不再坎坷!今天就给大家分享一个Github上全面的Java面试题大全,就是这份面试大全助我拿下大厂Offer,月薪提至30K!
我也是第一时间分享出来给大家,希望可以帮助大家都能去往自己心仪的大厂!为金三银四做准备!
一共有20个知识点专题,分别是:
JVM面试专题
Java并发面试专题
Kafka面试专题
MongDB面试专题
MyBatis面试专题
MySQL面试专题
Netty面试专题
RabbitMQ面试专题
Redis面试专题
Spring Cloud面试专题
SpringBoot面试专题
zookeeper面试专题
常见面试算法题汇总专题
计算机网络基础专题
设计模式专题
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
01069)]
MySQL面试专题
[外链图片转存中…(img-33ZiH3hg-1713440001070)]
Netty面试专题
[外链图片转存中…(img-GlO2msxb-1713440001070)]
RabbitMQ面试专题
[外链图片转存中…(img-5MjNDLAr-1713440001070)]
Redis面试专题
[外链图片转存中…(img-qOpvmynp-1713440001070)]
Spring Cloud面试专题
[外链图片转存中…(img-g71WSsPU-1713440001071)]
SpringBoot面试专题
[外链图片转存中…(img-6lEB61m4-1713440001071)]
zookeeper面试专题
[外链图片转存中…(img-Vh6DDL2G-1713440001071)]
常见面试算法题汇总专题
[外链图片转存中…(img-UDKuDLwy-1713440001071)]
计算机网络基础专题
[外链图片转存中…(img-uj80dLQF-1713440001072)]
设计模式专题
[外链图片转存中…(img-kfpV2GEF-1713440001072)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。