JUC锁框架源码阅读-AQS+Zookeeper实现分布式锁
时间:2021-09-10
本文章向大家介绍JUC锁框架源码阅读-AQS+Zookeeper实现分布式锁,主要包括JUC锁框架源码阅读-AQS+Zookeeper实现分布式锁使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
介绍
1.创建一个永久节点
2.竞争锁的时候同样的的key 所有线程都往永久节点插入指定key name的临时节点(节点不允许重复只会有一个插入成功)
3.插入失败的开启对永久节点的监听
4.当时获得锁的线程down机或者删除会触发监听。然后尝试获取CLH第一个线程节点 尝试重新获取锁
代码已上传github:https://github.com/aa310958153/zookeeper-lock
注:仅仅用于熟悉AQS如果要用到Zookeeper分布式锁直接使用Curator基于对Zookeeper锁的实现
InterProcessMutex:分布式可重入排它锁
InterProcessSemaphoreMutex:分布式排它锁
InterProcessReadWriteLock:分布式读写锁
InterProcessMultiLock:将多个锁作为单个实体管理的容器
加锁
@Override protected boolean tryAcquire(int acquires) { //获取当前线程 final Thread current = Thread.currentThread(); //获取锁状态 int c = getState(); //等于0表示 当前空闲状态可以尝试获取 <1>zkLock加锁 if (c == 0) { if (zkLock()&&compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //可重入判断 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
<1>zkLock
/** * zookeeper保存临时节点实现加锁 * @return */ public boolean zkLock() { String path= getLockPath(); boolean haveLock=false; try { curatorFramework .create() .creatingParentContainersIfNeeded() .withMode(CreateMode.EPHEMERAL) .forPath(path, syncValue.get().getValue().getBytes(StandardCharsets.UTF_8)); haveLock= true; } catch (org.apache.zookeeper.KeeperException.NodeExistsException e) {//重复的标识未获取到锁 haveLock=false; } catch (Exception e) { e.printStackTrace(); haveLock= false; } /** * 未获取到锁监听永久节点 */ if(!haveLock){ TreeCache treeCache = new TreeCache(CuratorClient.getCurator(), SYN_SWITCH_ZK_NODE); try { treeCache.start(); } catch (Exception e) { e.printStackTrace(); } if(!syncValue.get().isAddListener) { treeCache.getListenable().addListener(new TreeCacheListener() { @Override public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception { ChildData eventData = event.getData(); switch (event.getType()) { case NODE_ADDED: //System.out.println(path + "节点添加:" + eventData.getPath() + "\t添加数据为:" + new String(eventData.getData())); break; case NODE_UPDATED: // System.out.println(eventData.getPath() + "节点数据更新\t更新数据为:" + new String(eventData.getData()) + "\t版本为:" + eventData.getStat().getVersion()); break; case NODE_REMOVED: //监听到节点删除。表示锁正常释放 或者持有锁的服务断开连接 //获得第一个阻塞线程 唤醒 尝试获取锁 Thread firstThread=getFirstQueuedThread(); if( firstThread!=null) { LockSupport.unpark(firstThread); } break; default: break; } } }); syncValue.get().setAddListener(true); } } return haveLock; }
释放锁
@Override protected boolean tryRelease(int releases) { //状态-1 大于0的数字表示可重入加了多少次锁 int c = getState() - releases; //如果加锁线程非当前线程抛出异常 if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); //根据节点存储的值校验是否是当前线程加锁。如果不是抛出异常 String value; try { value= new String(curatorFramework.getData().forPath(getLockPath())); } catch (Exception e) { e.printStackTrace(); throw new IllegalMonitorStateException(); } if(value==null||!value.equals(syncValue.get().getValue())){ throw new IllegalMonitorStateException(); } boolean free = false; //当c等于0表示最后一次调用unlock 则进行锁的释放 if (c == 0) { free = true; //获得锁的线程设置为null setExclusiveOwnerThread(null); String path= getLockPath(); try { //删除节点 会触发节点监听 curatorFramework.delete().forPath(path); } catch (Exception e) { throw new IllegalMonitorStateException(); } syncValue.remove(); } //设置state setState(c); return free; }
原文地址:https://www.cnblogs.com/LQBlog/p/15250305.html
- 初体验 Ghost : yet another WordPress?
- 浅谈MySQL的事务隔离级别
- 国内环境下前端网页开发的几个“中国特色”代码
- 从源码的角度再看 React JS 中的 setState
- Sass 与Compass 在WordPress 主题开发中的运用
- Python爬虫Scrapy入门看这篇就够了
- Clef:为你的WordPress 站点添加两步验证
- JavaScript 基础(六) 数组方法 闭包
- 【译】WordPress 中的50个过滤器(4):第21-30个过滤器
- 【译】WordPress 中的50个过滤器(3):第11-20个过滤器
- 【译】WordPress 中的50个过滤器(2):先介绍10个过滤器
- 【译】WordPress 中的50个过滤器(1):何为过滤器?
- 哪种芯片架构将成为人工智能时代的开路先锋
- 算法系列(三)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php 中phar包的使用教程详解
- php微信公众号开发之快递查询
- Scrapy框架介绍之Puppeteer渲染的使用
- Keras设置以及获取权重的实现
- Java自动化测试(Android app界面元素 33)
- 太厉害了,这款开源类库可以帮你简化每一行代码
- Linux ps和pstree命令知识点总结
- CentOS7上以rpm方式安装JDK8
- linux DMA接口知识点详解
- Linux中使用crond工具创建定时任务的方法
- Linux which命令的具体使用
- Linux安装Python3.8.1的教程详解
- linux压缩文件命令zip的实例用法
- centos下samba文件夹共享服务器配置详解
- Centos7安装FFmpeg音/视频工具简易文档