1. package com.ysl.zkclient.queue;
  2.  
  3. import com.ysl.zkclient.ZKClient;
  4. import com.ysl.zkclient.exception.ZKNoNodeException;
  5. import com.ysl.zkclient.utils.ExceptionUtil;
  6. import org.apache.zookeeper.CreateMode;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9.  
  10. import java.io.Serializable;
  11. import java.util.List;
  12.  
  13. /**
  14. * 一种分布式队列的实现
  15. * @param <T>
  16. */
  17. public class ZKDistributedQueue<T extends Serializable> {
  18.  
  19. private static final Logger LOG = LoggerFactory.getLogger(ZKDistributedQueue.class);
  20.  
  21. private static final String ELEMENT_NAME = "node";
  22.  
  23. private ZKClient client;
  24. private String rootPath;
  25.  
  26. /**
  27. * 创建分布式队列
  28. * @param client zk客户端
  29. * @param rootPath 队列的跟路径
  30. */
  31. public ZKDistributedQueue(ZKClient client, String rootPath) {
  32. this.client = client;
  33. this.rootPath = rootPath;
  34. if(!client.exists(rootPath)){
  35. throw new ZKNoNodeException("the root path is not exists, please create path first ["+rootPath+"]");
  36. }
  37. }
  38.  
  39. /**
  40. * 添加一个元素
  41. * @param node
  42. * @return
  43. */
  44. public boolean offer(T node){
  45. try{
  46. client.create(rootPath+"/"+ELEMENT_NAME + "-",node, CreateMode.PERSISTENT_SEQUENTIAL);
  47. }catch (Exception e){
  48. throw ExceptionUtil.convertToRuntimeException(e);
  49. }
  50. return true;
  51. }
  52.  
  53. /**
  54. * 删除并返回顶部元素
  55. * @return
  56. */
  57. public T pool(){
  58. while(true){
  59. Node node = getFirstNode();
  60. if(node == null){
  61. return null;
  62. }
  63.  
  64. try{
  65. boolean flag = client.delete(node.getName());
  66. if(flag){
  67. return (T)node.getData();
  68. }else{
  69. //删除失败,说明数据已经被其他的线程获取,重新获取底部元素
  70. }
  71. }catch (Exception e){
  72. throw ExceptionUtil.convertToRuntimeException(e);
  73. }
  74. }
  75. }
  76.  
  77. /**
  78. * 获取队列顶部元素
  79. * @return
  80. */
  81. private Node<T> getFirstNode() {
  82. try{
  83. while(true){
  84. List<String> children = client.getChild(rootPath,true);
  85. if(children == null || children.isEmpty()){
  86. return null;
  87. }
  88.  
  89. String nodeName = getNodeName(children);
  90. try{
  91. return new Node<T>(rootPath+"/"+nodeName,(T)client.getData(rootPath+"/"+nodeName));
  92. }catch (ZKNoNodeException e){
  93. //如果抛出此异常,证明该节点已被其他线程获取
  94. }
  95. }
  96. }catch (Exception e){
  97. throw ExceptionUtil.convertToRuntimeException(e);
  98. }
  99. }
  100.  
  101. /**
  102. * 获取编号最小的节点
  103. * @param children
  104. * @return
  105. */
  106. private String getNodeName(List<String> children) {
  107. String child= children.get(0);
  108. for(String path : children){
  109. if(path.compareTo(child) < 0){
  110. child = path;
  111. }
  112. }
  113. return child;
  114. }
  115.  
  116. public boolean isEmpty(){
  117. return client.getChild(rootPath,true).size() == 0;
  118. }
  119.  
  120. public T peek(){
  121. Node<T> node = getFirstNode();
  122. if(node == null){
  123. return null;
  124. }
  125. return node.getData();
  126. }
  127.  
  128. private class Node<T>{
  129.  
  130. private String name;
  131. private T data;
  132.  
  133. public Node(String name, T data) {
  134. this.name = name;
  135. this.data = data;
  136. }
  137.  
  138. public String getName() {
  139. return name;
  140. }
  141.  
  142. public T getData() {
  143. return data;
  144. }
  145. }
  146. }

测试代码

  1. /**
  2. * 测试分布式队列
  3. * @throws Exception
  4. * @return void
  5. */
  6. @Test
  7. public void testDistributedQueue() throws Exception{
  8. final String rootPath = "/zk/queue";
  9. //创建rootPath
  10. zkClient.createRecursive(rootPath, null, CreateMode.PERSISTENT);
  11.  
  12. final List<String> list1 = new ArrayList<String>();
  13. final List<String> list2 = new ArrayList<String>();
  14. for(int i=0;i<21;i++){
  15. Thread thread1 = new Thread(new Runnable() {
  16. public void run() {
  17. ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
  18. queue.offer(Thread.currentThread().getName());
  19. list1.add(Thread.currentThread().getName());
  20. }
  21. });
  22. thread1.start();
  23. }
  24.  
  25. //等待事件到达
  26. int size1 = TestUtil.waitUntil(21, new Callable<Integer>() {
  27. @Override
  28. public Integer call() throws Exception {
  29. return list1.size();
  30. }
  31.  
  32. }, TimeUnit.SECONDS, 100);
  33. System.out.println(zkClient.getChildren(rootPath));
  34.  
  35. for(int i=0;i<20;i++){
  36. Thread thread = new Thread(new Runnable() {
  37. public void run() {
  38. ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
  39. list2.add(queue.poll());
  40. }
  41. });
  42. thread.start();
  43. }
  44. //等待事件到达
  45. int size2 = TestUtil.waitUntil(20, new Callable<Integer>() {
  46. @Override
  47. public Integer call() throws Exception {
  48. return list2.size();
  49. }
  50.  
  51. }, TimeUnit.SECONDS, 100);
  52. assertThat(size2).isEqualTo(20);
  53. boolean flag = true;
  54. for(int i =0;i<20;i++){
  55. if(!list1.get(i).equals(list2.get(i))){
  56. flag = false;
  57. break;
  58. }
  59. }
  60. assertThat(flag).isTrue();
  61.  
  62. ZKDistributedQueue<String> queue = new ZKDistributedQueue(zkClient, rootPath);
  63. assertThat(queue.peek()).isEqualTo(queue.poll());
  64. }

一种基于zookeeper的分布式队列的设计与实现的更多相关文章

  1. 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁

    一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...

  2. ZooKeeper实现分布式队列Queue

    ZooKeeper实现分布式队列Queue 让Hadoop跑在云端系列文章,介绍了如何整合虚拟化和Hadoop,让Hadoop集群跑在VPS虚拟主机上,通过云向用户提供存储和计算的服务. 现在硬件越来 ...

  3. 基于ZooKeeper的分布式Session实现(转)

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  4. 基于ZooKeeper的分布式Session实现

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  5. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...

  6. Java Web学习总结(20)——基于ZooKeeper的分布式session实现

    1.   认识ZooKeeper ZooKeeper-- "动物园管理员".动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始 ...

  7. 分布式锁(3) ----- 基于zookeeper的分布式锁

    分布式锁系列文章 分布式锁(1) ----- 介绍和基于数据库的分布式锁 分布式锁(2) ----- 基于redis的分布式锁 分布式锁(3) ----- 基于zookeeper的分布式锁 代码:ht ...

  8. 基于Zookeeper的分布式锁(干干干货)

    原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...

  9. 基于zookeeper实现分布式配置中心(二)

    上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...

随机推荐

  1. 详解JMeter正则表达式

    详解JMeter正则表达式(1) 1.概览 JMeter中包含范本匹配软件Apache Jakarta ORO .在Jakarta网站上有一些关于它的文档,例如a summary of the pat ...

  2. Maven系列(二)exec-maven-plugin

    Maven系列(二)exec-maven-plugin 1. mvn 命令行运行 # exec:java 不会自动编译代码,你需要手动执行 mvn compile 来完成编译 mvn compile ...

  3. postman模拟登录接口

    https://blog.csdn.net/qq_22219911/article/details/80235272

  4. C和指针小结(C/C++程序设计)

    C和指针 相关基础知识:内存的分配(谭浩强版) 1.整型变量的地址与浮点型/字符型变量的地址区别?(整型变量/浮点型变量的区别是什么) 2.int *p,指向整型数据的指针变量. 3.通过指针变量访问 ...

  5. 根据数据库的表生成项目,项目变为hibernate项目(实际开发中常用)

    1.  选择模式为Myeclipse Database Explorer perpective 2. (1)右键建立mysql模板,选择默认的mysql模板 (2)drive name (任意这里取m ...

  6. UVaLive 2531 The K-League (网络流)

    题意:有 n 个队伍进行比赛,每个队伍比赛数目是一样的,每场恰好一个胜一个负,给定每个队伍当前胜的场数败的数目,以及两个队伍剩下的比赛场数,问你冠军队伍可能是哪些队. 析:对每个队伍 i 进行判断是不 ...

  7. 20155216 2016-2017-2 《Java程序设计》第六周学习总结

    20155216 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 流与IO 将数据从来源中取出,可以使用输入串流:将数据写入目的地,可以使用输出串流,串流是有 ...

  8. spring boot docker 初尝试

    Docker服务中进程间通信通过/var/run/docker.sock实现,默认服务不提供监听端口,因此使用docker remote api 需要手动绑定端口. 在centos7.2下,可以进行这 ...

  9. PAT甲 1006. Sign In and Sign Out (25) 2016-09-09 22:55 43人阅读 评论(0) 收藏

    1006. Sign In and Sign Out (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue ...

  10. 逆着得最长路POJ1797

    POJ1797点击打开链接 这个题很是不错我感觉 很容易把这个题和上一个青蛙跳的题联系起来做,我也确实联系起来了,可还是没能完整得Ac,是因为我的算法思路还是最短路,这里错了 这个题目得要求是,从1到 ...