zookeeper分布式锁简单实现(JavaApi)
- 创建会话连接
package com.karat.cn.zookeeperAchieveLock.javaapilock; import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException;
import java.util.concurrent.CountDownLatch; /**
* 创建会话
*/
public class ZookeeperClient { private final static String CONNECTSTRING="47.107.121.215:2181"; private static int sessionTimeout=5000; //获取连接
public static ZooKeeper getInstance() throws IOException, InterruptedException {
final CountDownLatch conectStatus=new CountDownLatch(1);
ZooKeeper zooKeeper=new ZooKeeper(CONNECTSTRING, sessionTimeout, new Watcher() {
public void process(WatchedEvent event) {
if(event.getState()== Event.KeeperState.SyncConnected){//连接成功状态
conectStatus.countDown();
}
}
});
conectStatus.await();//等待
return zooKeeper;
} public static int getSessionTimeout() {
return sessionTimeout;
}
}
- 临时节点删除监控
package com.karat.cn.zookeeperAchieveLock.javaapilock; import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher; import java.util.concurrent.CountDownLatch; /**
*监控
*/
public class LockWatcher implements Watcher{ private CountDownLatch latch; public LockWatcher(CountDownLatch latch) {
this.latch = latch;
} public void process(WatchedEvent event) {
if(event.getType()== Event.EventType.NodeDeleted){//当前节点是否删除
latch.countDown();
}
}
}
- 上锁与释放锁
package com.karat.cn.zookeeperAchieveLock.javaapilock; import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper; import java.io.IOException;
import java.util.List;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; /**
* 分布式锁的实现
*/
public class DistributeLock { private static final String ROOT_LOCKS="/LOCKS";//根节点 private ZooKeeper zooKeeper;//zooKeeper实列 private int sessionTimeout; //会话超时时间 private String lockID; //记录锁节点id private final static byte[] data={1,2}; //节点的数据 private CountDownLatch countDownLatch=new CountDownLatch(1);//计数器 //会话连接
public DistributeLock() throws IOException, InterruptedException {
this.zooKeeper=ZookeeperClient.getInstance();
this.sessionTimeout=ZookeeperClient.getSessionTimeout();
} //获取锁的方法
public boolean lock(){
try {
//创建一个临时有序节点
lockID=zooKeeper.create(ROOT_LOCKS+"/",data, ZooDefs.Ids.
OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(Thread.currentThread().getName()
+"->成功创建了lock节点["+lockID+"], 开始去竞争锁");
//获取当前根节点下的所有子节点
List<String> childrenNodes=zooKeeper.getChildren(ROOT_LOCKS,true);//获取根节点下的所有子节点
//排序,从小到大(树节点)
SortedSet<String> sortedSet=new TreeSet<String>();
for(String children:childrenNodes){
sortedSet.add(ROOT_LOCKS+"/"+children);
}
String first=sortedSet.first(); //拿到最小的节点
if(lockID.equals(first)){//如果刚创建的临时节点就是最小节点,那么就没有其它子节点,当前新建节点获取锁成功
//表示当前就是最小的节点
System.out.println(Thread.currentThread().getName()+"->成功获得锁,lock节点为:["+lockID+"]");
return true;
}
//当当前创建的临时节点不是最小节点时,说明之前已有创建的临时节点,之前临时节点正在使用锁,等待锁释放
SortedSet<String> lessThanLockId=sortedSet.headSet(lockID);
if(!lessThanLockId.isEmpty()){
String prevLockID=lessThanLockId.last();//拿到比当前LOCKID这个几点更小的上一个节点
zooKeeper.exists(prevLockID,new LockWatcher(countDownLatch));//监控是否有删除节点的操作(释放锁)
countDownLatch.await(sessionTimeout, TimeUnit.MILLISECONDS);//等待锁释放(会话超时时间)
//上面这段代码意味着如果会话超时或者节点被删除(释放)了
System.out.println(Thread.currentThread().getName()+" 成功获取锁:["+lockID+"]");
}
return true;
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
//释放锁
public boolean unlock(){
System.out.println(Thread.currentThread().getName()
+"->开始释放锁:["+lockID+"]");
try {
zooKeeper.delete(lockID,-1);//删除当前节点(释放锁)
System.out.println("节点["+lockID+"]成功被删除");
return true;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
return false;
} public static void main(String[] args) {
final CountDownLatch latch=new CountDownLatch(10);
Random random=new Random();
for(int i=0;i<10;i++){
new Thread(()->{
DistributeLock lock=null;
try {
lock=new DistributeLock();//会话连接
latch.countDown();//减一
latch.await();//等待
lock.lock();//获取锁
Thread.sleep(random.nextInt(500));//睡眠
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if(lock!=null){
lock.unlock();//释放锁
}
}
}).start();//启动线程
}
}
}
使用zookeeper实现分布式锁中:当所有请求(线程)去竞争某一资源时,通过创建的节点是否是最小节点来实现锁功能,如果当前线程创建的是最小节点(说明自己是第一个创建的节点),那么代表自己获取了锁,如果当前线程创建的不是最小节点,那么通过监听去了解上一级比自己小的节点是否有删除动作(锁释放),如果监听到上一级比自己小的节点有删除节点操作,那么自己就能够获取到锁。通过api方式实现能够在demo中跑起来,但是用ab并发测试,会报错,可以使用zookeeper客户端Curator中的InterProcessMutex来实现锁功能,并发测试不报错。
zookeeper分布式锁简单实现(JavaApi)的更多相关文章
- ZooKeeper分布式锁简单实践
ZooKeeper分布式锁简单实践 在分布式解决方案中,Zookeeper是一个分布式协调工具.当多个JVM客户端,同时在ZooKeeper上创建相同的一个临时节点,因为临时节点路径是保证唯一,只要谁 ...
- Zookeeper 分布式锁 (图解+秒懂+史上最全)
文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...
- [转载] zookeeper 分布式锁服务
转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...
- 跟着大神学zookeeper分布式锁实现-----来自Ruthless
前几天分享了@Ruthless大神的Redis锁,发现和大家都学习了很多东西.因为分布式锁里面,最好的实现是zookeeper的分布式锁.所以在这里把实现方式和大家分享一下. zookeeper分布式 ...
- 关于分布式锁原理的一些学习与思考-redis分布式锁,zookeeper分布式锁
首先分布式锁和我们平常讲到的锁原理基本一样,目的就是确保,在多个线程并发时,只有一个线程在同一刻操作这个业务或者说方法.变量. 在一个进程中,也就是一个jvm 或者说应用中,我们很容易去处理控制,在j ...
- zookeeper 分布式锁原理
zookeeper 分布式锁原理: 1 大家也许都很熟悉了多个线程或者多个进程间的共享锁的实现方式了,但是在分布式场景中我们会面临多个Server之间的锁的问题,实现的复杂度比较高.利用基于googl ...
- 分布式锁(一) Zookeeper分布式锁
什么是Zookeeper? Zookeeper(业界简称zk)是一种提供配置管理.分布式协同以及命名的中心化服务,这些提供的功能都是分布式系统中非常底层且必不可少的基本功能,但是如果自己实现这些功能而 ...
- ZooKeeper 分布式锁
在Redis分布式锁一文中, 作者介绍了如何使用Redis开发分布式锁. Redis分布式锁具有轻量高吞吐量的特点,但是一致性保证较弱.我们可以使用Zookeeper开发分布式锁,来满足对高一致性的要 ...
- ZooKeeper分布式锁的实现原理
七张图彻底讲清楚ZooKeeper分布式锁的实现原理[石杉的架构笔记] 文章转载自:https://juejin.im/post/5c01532ef265da61362232ed#comment(写的 ...
随机推荐
- 问题:C# ToString("P");结果:c#中的常用ToString()方法总结
c#中的常用ToString()方法总结 很多类都重写了ToString方法, 导致很多类的tostring到底执行了什么,有哪些参数,都不清楚 对于int,double等的tostring: C ...
- ios下编译opencv
如果想要在ios下编译opencv 需要安装Cmake 这里通过homebrew 来安装cmake ios下打开终端然后先安装 homebrew :(mac 下自带ruby) ruby -e &quo ...
- cygwin选择安装包选项搭建NDK开发环境/配置cygwin的root权限
9.Search是可以输入你要下载的包的名称,能够快速筛选出你要下载的包.那四个单选按钮是选择下边树的样式,默认就行,不用动.View默认是Category,建议改成full显示全部包再查,省的一些包 ...
- DAY12-前端之HTML
一.html初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ...
- 安卓SQLite数据库操作(下)
在安卓开发中,数据库的操作无非就是增删改查.那么,这里我们通过例子来学习这四个操作. 我们先看代码吧.具体讲解后面说. 布局文件 activity_main.xml <LinearLayout ...
- hadoop-eclipse-plugin-2.6.0-cdh5.4.0 插件编译
1.JDK配置 1) 安装jdk 2) 配置环境变量 JAVA_HOME.CLASSPATH.PATH等设置 2.Eclipse 1).下载eclipse-jee-juno-SR2.rar 2).解压 ...
- javascript的概述
JavaScript是怎么诞生的???刚开始的是为了验证表单而开发出来的. 什么是JavaScript???a.面向对象的编程语言b.解释性的编程语言(说白了就是不用编译的一种语言)c.脚本语言(说白 ...
- 从公交塞车,看C#多线程问题(转)
好久没写博客了,可能是因为最近工作太过于压抑的原因吧!有点颓废了.... 而且公司距离住处要坐公交将近40--50分钟(各个原因,纠结中ing...),提前一个半小时起床,居然还能迟到!因为距离公司前 ...
- go语言linux环境配置
linux的设置方法:有4个环境变量需要设置:GOROOT.GOPATH.GOBIN以及PATH.需要设置到某一个profile文件中(~/.bash_profile(单一用户)或/etc/profi ...
- ROS Learning-007 beginner_Tutorials ROS节点
ROS Indigo beginner_Tutorials-06 ROS节点 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.04.4 LT ...