一种基于zookeeper的分布式队列的设计与实现
package com.ysl.zkclient.queue; import com.ysl.zkclient.ZKClient;
import com.ysl.zkclient.exception.ZKNoNodeException;
import com.ysl.zkclient.utils.ExceptionUtil;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.Serializable;
import java.util.List; /**
* 一种分布式队列的实现
* @param <T>
*/
public class ZKDistributedQueue<T extends Serializable> { private static final Logger LOG = LoggerFactory.getLogger(ZKDistributedQueue.class); private static final String ELEMENT_NAME = "node"; private ZKClient client;
private String rootPath; /**
* 创建分布式队列
* @param client zk客户端
* @param rootPath 队列的跟路径
*/
public ZKDistributedQueue(ZKClient client, String rootPath) {
this.client = client;
this.rootPath = rootPath;
if(!client.exists(rootPath)){
throw new ZKNoNodeException("the root path is not exists, please create path first ["+rootPath+"]");
}
} /**
* 添加一个元素
* @param node
* @return
*/
public boolean offer(T node){
try{
client.create(rootPath+"/"+ELEMENT_NAME + "-",node, CreateMode.PERSISTENT_SEQUENTIAL);
}catch (Exception e){
throw ExceptionUtil.convertToRuntimeException(e);
}
return true;
} /**
* 删除并返回顶部元素
* @return
*/
public T pool(){
while(true){
Node node = getFirstNode();
if(node == null){
return null;
} try{
boolean flag = client.delete(node.getName());
if(flag){
return (T)node.getData();
}else{
//删除失败,说明数据已经被其他的线程获取,重新获取底部元素
}
}catch (Exception e){
throw ExceptionUtil.convertToRuntimeException(e);
}
}
} /**
* 获取队列顶部元素
* @return
*/
private Node<T> getFirstNode() {
try{
while(true){
List<String> children = client.getChild(rootPath,true);
if(children == null || children.isEmpty()){
return null;
} String nodeName = getNodeName(children);
try{
return new Node<T>(rootPath+"/"+nodeName,(T)client.getData(rootPath+"/"+nodeName));
}catch (ZKNoNodeException e){
//如果抛出此异常,证明该节点已被其他线程获取
}
}
}catch (Exception e){
throw ExceptionUtil.convertToRuntimeException(e);
}
} /**
* 获取编号最小的节点
* @param children
* @return
*/
private String getNodeName(List<String> children) {
String child= children.get(0);
for(String path : children){
if(path.compareTo(child) < 0){
child = path;
}
}
return child;
} public boolean isEmpty(){
return client.getChild(rootPath,true).size() == 0;
} public T peek(){
Node<T> node = getFirstNode();
if(node == null){
return null;
}
return node.getData();
} private class Node<T>{ private String name;
private T data; public Node(String name, T data) {
this.name = name;
this.data = data;
} public String getName() {
return name;
} public T getData() {
return data;
}
}
}
测试代码
/**
* 测试分布式队列
* @throws Exception
* @return void
*/
@Test
public void testDistributedQueue() throws Exception{
final String rootPath = "/zk/queue";
//创建rootPath
zkClient.createRecursive(rootPath, null, CreateMode.PERSISTENT); final List<String> list1 = new ArrayList<String>();
final List<String> list2 = new ArrayList<String>();
for(int i=0;i<21;i++){
Thread thread1 = new Thread(new Runnable() {
public void run() {
ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
queue.offer(Thread.currentThread().getName());
list1.add(Thread.currentThread().getName());
}
});
thread1.start();
} //等待事件到达
int size1 = TestUtil.waitUntil(21, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return list1.size();
} }, TimeUnit.SECONDS, 100);
System.out.println(zkClient.getChildren(rootPath)); for(int i=0;i<20;i++){
Thread thread = new Thread(new Runnable() {
public void run() {
ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
list2.add(queue.poll());
}
});
thread.start();
}
//等待事件到达
int size2 = TestUtil.waitUntil(20, new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return list2.size();
} }, TimeUnit.SECONDS, 100);
assertThat(size2).isEqualTo(20);
boolean flag = true;
for(int i =0;i<20;i++){
if(!list1.get(i).equals(list2.get(i))){
flag = false;
break;
}
}
assertThat(flag).isTrue(); ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
assertThat(queue.peek()).isEqualTo(queue.poll());
}
一种基于zookeeper的分布式队列的设计与实现的更多相关文章
- 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁
一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...
- ZooKeeper实现分布式队列Queue
ZooKeeper实现分布式队列Queue 让Hadoop跑在云端系列文章,介绍了如何整合虚拟化和Hadoop,让Hadoop集群跑在VPS虚拟主机上,通过云向用户提供存储和计算的服务. 现在硬件越来 ...
- 基于ZooKeeper的分布式Session实现(转)
1. 认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...
- 基于ZooKeeper的分布式Session实现
1. 认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...
- 基于 Zookeeper 的分布式锁实现
1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...
- Java Web学习总结(20)——基于ZooKeeper的分布式session实现
1. 认识ZooKeeper ZooKeeper-- "动物园管理员".动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始 ...
- 分布式锁(3) ----- 基于zookeeper的分布式锁
分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...
- 基于Zookeeper的分布式锁(干干干货)
原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...
- 基于zookeeper实现分布式配置中心(二)
上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...
随机推荐
- [Selenium]验证点了某个Button之后无反应
期望:点了某个Button,无反应 问题:怎么去验证无反应 WebElement webElement = page.getICORemove(); SeleniumUtil.hover(page.g ...
- Tomcat连接池配置
今日做了个小网站,数据量不大,但当发布到虚拟主机上之后,接连不断的遇到各种问题. 被折磨了数日后,在网上查了大量的相关资料,现总结如下. 一.项目在上传到远程服务器的过程中,有可能丢失文件,或文件内容 ...
- vs 2015 运行安卓报错
vs2015 start Android 错误信息如下: Severity Code Description Project File Line Suppression StateError java ...
- 命名空间namespace ,以及重复定义的问题解析
名字空间是用来划分冲突域的,把全局名字空间划分成几个小的名字空间.全局函数,全局变量,以及类的名字是在同一个全局名字空间中,有时为了防止命名冲突,会把这些名字放到不同的名字空间中去. 首先我们看一下名 ...
- Windows Server 2012如何实现双网卡绑定
在windows server 2012 之前我们在服务器上如果要实现双网卡绑定则需要向服务器厂家所要相应的软件,但是现在强大的windows server 2012的到来使我们省去了所有的麻烦,因为 ...
- hdu-1181(bfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1181 思路:bfs,就是每次找到匹配麻烦一点,注意如果结尾和开头相同,就不算. #include< ...
- Windows 下安装mysql总结
1.配置环境变量 将安装目录添加到系统路径 我的电脑->属性->高级->环境变量->path 2.修改my.ini 位于解压安装目录下 在其中修改或添加配置: [mysqld] ...
- Linux服务器部署系列之一—Apache篇(上)
Linux系统的应用越来越广泛了,学习linux系统的网管兄弟也有增加的趋势.很久以前就有些想法,要将自己学的linux知识整理一下.最近,终于下定决心,挤出时间开始动手写些东西了.虽然不一定好,不过 ...
- hdu 5038 求出现次数最多的grade
http://acm.hdu.edu.cn/showproblem.php?pid=5038 模拟水题 求出现次数最多的grade.如果有多个grade出现的次数一样多,且还有其他的grade,则把这 ...
- Bellman_ford货币兑换——正权回路判断
POJ1860 题目大意:你在某一点有一些钱,给定你两点之间钱得兑换规则,问你有没有办法使你手里的钱增多.就是想看看转一圈我的钱能不能增多,出现这一点得条件就是有兑换钱得正权回路,所以选择用bellm ...