package com.zero.zookeeper; import java.io.IOException; import java.util.List; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.Watcher.Event.EventType; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.Stat; public class DistributedQueue { private static DistributedQueue instance = new DistributedQueue(); private static ZooKeeper zookeeper; private String dir = "/distributedQueue"; private String prefix = "queueIndex"; private DistributedQueue() { if (null != instance) { throw new AssertionError(); } try { zookeeper = new ZooKeeper("localhost:2181", 10000, null); } catch (IOException e) { e.printStackTrace(); } } public static DistributedQueue getInstanceQueue() { return instance; } public byte[] take() throws KeeperException, InterruptedException { return take(Long.MAX_VALUE); } public byte[] take(long time) throws KeeperException, InterruptedException { while (true) { LatchChildWatcher childWatcher = new LatchChildWatcher(); TreeMap<Long, String> orderedChildren; try { orderedChildren = (TreeMap<Long, String>) orderChildren(childWatcher); } catch (KeeperException.NoNodeException e) { zookeeper.create(dir, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); continue; } if (orderedChildren.size() == 0) { // 等待时间超时,则返回 false,否则返回 true boolean idNotified = childWatcher.await(time); if (idNotified) { continue; } return null; } for (String childNode : orderedChildren.values()) { try { byte[] data = zookeeper.getData(childNode, false, null); zookeeper.delete(childNode, -1);// 也会触发NodeChildrenChanged return data; } catch (KeeperException.NoNodeException e) { } } } } /** * 将数据插入队列中 * * @param data * @return * @throws KeeperException * @throws InterruptedException */ public boolean offer(byte[] data) throws KeeperException, InterruptedException { for (;;) { try { zookeeper.create(dir + "/" + prefix, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); return true; } catch (KeeperException.NoNodeException e) { zookeeper.create(dir, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } } } public static void close() { try { zookeeper.close(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private TreeMap<Long, String> orderChildren(Watcher watcher) throws NoNodeException { Stat stat = null; try { stat = zookeeper.exists(dir, true);// 这里如果加watcher,会监控dir的NodeCreated与NodeDeleted } catch (KeeperException | InterruptedException e) { e.printStackTrace(); } if (stat == null) { throw new KeeperException.NoNodeException(); } List<String> childernList = null; try { childernList = zookeeper.getChildren(dir, watcher);// 这里如果加watcher,会监控dir的NodeChildrenChanged } catch (KeeperException | InterruptedException e) { e.printStackTrace(); } TreeMap<Long, String> orderedChildren = new TreeMap<Long, String>(); for (String childNode : childernList) { try { String childNodePath = dir + "/" + childNode; Stat s = zookeeper.exists(childNodePath, true); if (s != null) {// 多线程下可能zookeeper.getChildren后childNode被删除 orderedChildren.put(s.getCzxid(), childNodePath); } } catch (KeeperException | InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return orderedChildren; } /** * Watcher是一次性,只会触发一次process,除非多次设置zookeeper.getChildren(dir, watcher) * * @author zero * */ private class LatchChildWatcher implements Watcher { private volatile boolean isNotify = false; @Override public void process(WatchedEvent event) { if (EventType.NodeChildrenChanged == event.getType()) { isNotify = true; } } public boolean await(long time) throws InterruptedException { long end = System.currentTimeMillis() + time * 1000; for (;;) { TimeUnit.MILLISECONDS.sleep(100); if (isNotify) { return true; } else if (System.currentTimeMillis() >= end) { return false; } } } } }