zookeeper应用场景练习(分布式锁)
在寻常的高并发的程序中。为了保证数据的一致性。因此都会用到锁。来对当前的线程进行锁定。在单机操作中。非常好做到,比方能够採用Synchronized、Lock或者其它的读写多来锁定当前的线程。可是在分布式的系统中,就非常难做到这一点。因此能够採用zookeeper中节点的特性来满足这一点。
大致实现的思路例如以下。
1.每一个客户端都去zookeeper上创建暂时的顺序节点
2.客户端推断当前自己创建的节点是不是最小的
3.假设是的话,就获得了运行当前任务的锁
4.假设不是的话。就找到比自己小的节点,然后进行监听,假设被删除的话。就能够获得锁
上面就是大致的实现思路,以下我们来通过代码来实现一下。
package com.test; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch; import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class DistributedLock { private String lockName;
private final int timeOut = 3000;
private final String root = "/locks";
private String myZnode;// 代表当前节点信息
private String waitZnode;
private static Logger logger = LoggerFactory
.getLogger(DistributedLock.class);
private CuratorFramework client;
private CountDownLatch latch = new CountDownLatch(1); public DistributedLock(String connectString, String lockName) {
this.lockName = lockName;
client = CuratorFrameworkFactory.builder().connectionTimeoutMs(timeOut)
.connectString(connectString)
.retryPolicy(new RetryNTimes(3, 3000)).build();
ConnectionStateListener listener = new ConnectionStateListener() { public void stateChanged(CuratorFramework client,
ConnectionState newState) {
if (newState == ConnectionState.CONNECTED) {
logger.info("连接成功了");
latch.countDown();
}
}
}; client.getConnectionStateListenable().addListener(listener);
client.start();
try {
latch.await();
createRoot();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* @Title: 创建根节点root
* @Description: TODO
* @param
* @return void
* @throws
*/
private void createRoot() {
try {
Stat stat = client.checkExists().forPath(root);
if (stat != null) {
logger.info("root has already exists");
} else {
// 创建跟节点
client.create().creatingParentsIfNeeded().forPath(root); }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public void getLocks() { try {
myZnode = client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(root + "/" + lockName);
logger.info(myZnode + "has created");
// 取出全部的子节点。然后找出比自己小的节点。进行监听的设置
List<String> subNodes = client.getChildren().forPath(root);
// 取出全部带有lockname的节点信息
List<String> lockObjNodes = new ArrayList<String>();
for (String node : subNodes) {
if (node.contains(lockName)) {
lockObjNodes.add(node);
}
}
// 对当前节点进行排序
Collections.sort(lockObjNodes);
// 推断当前的节点是不是最小的节点
if (myZnode.equals(root + "/" + lockObjNodes.get(0))) {
doAction();
} else {
// 找到比自己节点大一的节点进行监听
String subMyZone = myZnode
.substring(myZnode.lastIndexOf("/") + 1);
waitZnode = lockObjNodes.get(Collections.binarySearch(
lockObjNodes, subMyZone) - 1);
// 对节点进行监听
Stat stat = client.checkExists()
.usingWatcher(deleteNodeWatcher).forPath("/"+waitZnode);
if (stat != null) {
System.out.println(Thread.currentThread().getName()
+ "处于等待状态");
} else {
doAction();
}
}
} catch (Exception e) {
logger.error(e.getMessage());
}
} // 删除节点的事件监听
CuratorWatcher deleteNodeWatcher = new CuratorWatcher() { public void process(WatchedEvent event) throws Exception { if (event.getType() == EventType.NodeDeleted) {
doAction();
}
}
}; private void doAction() {
System.out.println(Thread.currentThread().getName() + "開始运行");
client.close();
}
}
以下来測试一下
/**
* @FileName: TestCurrentZk.java
* @Package:com.test
* @Description: TODO
* @author: LUCKY
* @date:2016年2月2日 下午11:36:04
* @version V1.0
*/
package com.test; /**
* @ClassName: TestCurrentZk
* @Description: TODO
* @author: LUCKY
* @date:2016年2月2日 下午11:36:04
*/
public class TestCurrentZk { public static void main(String[] args) throws Exception {
Thread threads[] = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
ClientTest clientTest = new ClientTest(
"100.66.162.36:2181", "locknametest");
clientTest.getLocks();
}
}); threads[i].start(); }
Thread.sleep(Integer.MAX_VALUE);
}
}
zookeeper应用场景练习(分布式锁)的更多相关文章
- zookeeper适用场景:分布式锁实现
问题导读:1.zookeeper如何实现分布式锁?2.什么是羊群效应?3.zookeeper如何释放锁? 在zookeeper应用场景有关于分布式集群配置文件同步问题的描述,设想一下如果有100台机器 ...
- Zookeeper是如何实现分布式锁的
[toc] Zookeeper是如何实现分布式锁的 标签 : Zookeeper 分布式 实现分布式锁要考虑的重要问题 1. 三个核心要素 加锁, 解锁, 锁超时 2. 三个问题 要保证原子性操作, ...
- ZooKeeper典型应用场景:分布式锁
分布式锁是控制分布式系统之间同步访问共享资源的一种方式.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致 ...
- Zookeeper绍二(分布式锁介)
一.为什么会有分布式锁? 在多线程环境下,由于上下文的切换,数据可能出现不一致的情况或者数据被污染,我们需要保证数据安全,所以想到了加锁. 所谓的加锁机制呢,就是当一个线程访问该类的某个数据时,进行保 ...
- 服务注册中心之ZooKeeper系列(三) 实现分布式锁
通过ZooKeeper的有序节点.节点路径不回重复.还有节点删除会触发Wathcer事件的这些特性,我们可以实现分布式锁. 一.思路 zookeeper中创建一个根节点Locks,用于后续各个客户端的 ...
- zookeeper【5】分布式锁
我们常说的锁是单进程多线程锁,在多线程并发编程中,用于线程之间的数据同步,保护共享资源的访问.而分布式锁,指在分布式环境下,保护跨进程.跨主机.跨网络的共享资源,实现互斥访问,保证一致性. 架构图: ...
- 基于zookeeper或redis实现分布式锁
前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...
- 基于ZooKeeper的三种分布式锁实现
[欢迎关注公众号:程序猿讲故事 (codestory),及时接收最新文章] 今天介绍基于ZooKeeper的分布式锁的简单实现,包括阻塞锁和非阻塞锁.同时增加了网上很少介绍的基于节点的非阻塞锁实现,主 ...
- 跟着实例学习ZooKeeper的用法: 分布式锁
锁 分布式的锁全局同步, 这意味着任何一个时间点不会有两个客户端都拥有相同的锁. 可重入锁Shared Reentrant Lock 首先我们先看一个全局可重入的锁. Shared意味着锁是全局可见的 ...
- Zookeeper系列3 实现分布式锁
基本思路 1 client调用create()方法创建“/locks/_lock_”临时顺序节点,注意节点类型是EPHEMERAL_SEQUENTIAL 2 client调用getChildren(& ...
随机推荐
- 使用uglifyjs压缩JS
一般vue项目完成打包以后需要优化,特别是首次打开加载速度们,webpack打包以后js文件体积很大等方法,可以用这个方法来压缩js文件 安装node.js 安装当前应用 -- uglifyjs 如何 ...
- 从字节码指令看重写在JVM中的实现
Java是解释执行的.包含动态链接的特性.都给解析或执行期间提供了非常多灵活扩展的空间.面向对象语言的继承.封装和多态的特性,在JVM中是怎样进行编译.解析,以及通过字节码指令怎样确定方法调用的版本号 ...
- web服务启动spring自己主动运行ApplicationListener的使用方法
我们知道.一般来说一个项目启动时须要载入或者运行一些特殊的任务来初始化系统.通常的做法就是用servlet去初始化.可是servlet在使用spring bean时不能直接注入,还须要在web.xml ...
- 亚马逊AWS学习——多网络接口下配置EC2实例连接公网的一个“bug”
转载请注明出处:http://blog.csdn.net/dongdong9223/article/details/47667627 本文出自[我是干勾鱼的博客] 之前在<亚马逊AWS学习--E ...
- bzoj1019: [SHOI2008]汉诺塔(动态规划)
1019: [SHOI2008]汉诺塔 题目:传送门 简要题意: 和经典的汉诺塔问题区别不大,但是题目规定了一个移动时的优先级: 如果当前要从A柱子移动,但是A到C的优先级比A到B的优先级大的话,那就 ...
- 用ksh运行一个helloworld
本文目的在于记录和回顾.不建议当教程. Linux上没有ksh的话yum install ksh就可以了 直接上图 vim一个文件后缀名是ksh 内容是和shell差不多 然后赋予这个文件可执行权限 ...
- hbase的命令
1.1. 命令 名称 命令表达式 创建表 create '表名', '列族名1','列族名2','列族名N' 查看所有表 list 描述表 describe ‘表名’ 判断表存在 exists ' ...
- Win7 利用批处理文件结束进程
@echo offtitle 结束进程正在进行... ::结束进程TeamViewer.exewmic process where name="TeamViewer.exe" ca ...
- 从SQL注入谈数据访问层
什么是SQL注入? SQL注入就是应用程序的开发人员未预期的吧SQL语句传入到应用程序的过程,如果直接使用用户输入的值来构建SQL语句的应用程序是很可能会受到SQL注入攻击的.特别是基于浏览器的网络应 ...
- P3809 【模版】后缀排序
题目背景 这是一道模版题. 题目描述 读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置.位置编 ...