Zookeeper实现分布式队列(非阻塞式)

、队列中提供入队方法offer( T ), 出队方法 poll().
首先初始化参数

    protected final ZooKeeper zkClient;
    //queue节点
    protected final String root;
    //顺序节点前缀
    protected static final String Node_NAME="n_";
    //root队列跟节点
    public SimpleDistributedQueue(ZooKeeper zkClient, String root) {
        this.zkClient = zkClient;
        this.root = root;
    }

offer()方法的实现

public boolean offer(T element) throws Exception {
        //1拼接顺序节点路径
        String nodeFullPath=root.concat("/").concat(Node_NAME);
        try {
            //以对象流输出到内存,获取byte[]内容
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(bos);
            oos.writeObject(element);
            oos.flush();
            //2.创建持久顺序节点
            zkClient. create(nodeFullPath,bos.toByteArray(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        }catch (KeeperException.NoNodeException e){
            //如果没有跟节点就创建跟节点
            zkClient.create(root,"".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            //重新调用offer操作
            offer(element);
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
        return true;
    }

Poll()方法的实现

 public T poll() throws Exception{
        try {
            //1.获取所有顺序节点
            List<String>list=zkClient.getChildren(root,false);
            if (list.size()==0){
                return null;
            }
            //2.排序
            Collections.sort(list, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return getNodeNumber(o1,Node_NAME).compareTo(getNodeNumber(o2,Node_NAME));
                }
            });
            //3.循环每个顺序节点名
            for (String nodeName:list){
                //构造出顺序节点的完整路径
                String nodeFullPath=root.concat("/").concat(nodeName);
                try {
                    //4.读取顺序节点内容
                    Stat stat=new Stat();
                    byte[] content=zkClient.getData(nodeFullPath,false,stat);
                    //5.删除顺序节点
                    zkClient.delete(nodeFullPath,zkClient.exists(nodeFullPath,true).getVersion());
                    ByteArrayInputStream bis= new ByteArrayInputStream(content);
                    ObjectInputStream oos=new ObjectInputStream(bis);
                    //6.返回此节点内容
                    return (T) oos.readObject();
                }catch (Exception e){
                    //ignore由其他客户端把这个顺序节点消费掉
                    e.printStackTrace();
                }
            }

        }catch (Exception e){
           throw new RuntimeException(e);
        }

        return null;
    }

获取字节上数字序号

    private String getNodeNumber(String str, String nodeName) {
        int index=str.lastIndexOf(nodeName);
        if(index>=0){
            index+=Node_NAME.length();
            return index<=str.length() ? str.substring(index) : "";
        }
        return str;
    }

测试:存数据

        ZkHelper zkHelper=new ZkHelper();
        ZooKeeper zkClient=zkHelper.connect();
        final SimpleDistributedQueue<Order> queue=new SimpleDistributedQueue<>(zkClient,"/Queue");
        //生产线程
        new Thread(new ProducerThread(queue)).start();

查看zookeeper端
请添加图片描述

测试:设置多个消费者一个生产者,消费的速度大于生产,供不应求

        ZkHelper zkHelper=new ZkHelper();
        ZooKeeper zkClient=zkHelper.connect();
        final SimpleDistributedQueue<Order> queue=new SimpleDistributedQueue<>(zkClient,"/Queue");
        //消费线程,offer
        new Thread(new ConsumerThread(queue)).start();
        //生产线程,poll
        new Thread(new ProducerThread(queue)).start();
        new Thread(new ConsumerThread(queue)).start();

测试如下
Zookeeper实现分布式队列(非阻塞式)_第1张图片

你可能感兴趣的:(zookeeper,分布式,java)