基于zookeeper的分布式锁

其实现如下代码:

public class DistributedLock implements Lock {

    private static final Logger logger = LoggerFactory.getLogger(DistributedLock.class);

    private ZooKeeper zooKeeper = null;
    /**
     * 锁根节点目录
     */
    private final String LOCK_ROOT = "/locks";
    /**
     * 当前节点
     */
    private String currentNode;
    /**
     * 获取需要监控的前一个节点
     */
    private String prevNode;
    /**
     * 当前已获得锁节点
     */
    private String lockedBy;
    /**
     * 节点名称
     */
    private String nodeName;
    /**
     * 线程阻塞器
     */
    private CountDownLatch latch;

    public DistributedLock() {
        this("/lock");
    }

    public DistributedLock(String nodeName) {
        this("192.168.52.128:2181", 60000, nodeName);
    }

    public DistributedLock(String connectString, int sessionTimeout, String nodeName) {
        this.nodeName = nodeName;
        initZooKeeper(connectString, sessionTimeout);
        latch = new CountDownLatch(1);
    }

    /**
     * 初始化zookeeper
     * @param connectString
     * @param sessionTimeout
     */
    public void initZooKeeper(String connectString, int sessionTimeout) {
        try {
            //创建zookeeper实例,Watcher:监控节点变化的事件
            zooKeeper = new ZooKeeper(connectString, sessionTimeout, new ZKWatcher());
            //判断锁对应的根节点是否存在
            Stat stat = zooKeeper.exists(LOCK_ROOT, false);
            if(null == stat) {
                zooKeeper.create(LOCK_ROOT, LOCK_ROOT.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void lock() {
        if(!tryLock()) {
            //阻塞
            await();
        }
        logger.info("线程{}获取锁{}", Thread.currentThread().getName(), currentNode);
    }

    /**
     * 阻塞线程,直到latch计数countDown=0
     */
    private void await() {
        try {
            Stat stat = zooKeeper.exists(prevNode, true);
            if(null != stat) {
                logger.info("线程{}被阻塞,当前锁{}", Thread.currentThread().getName(), lockedBy);
                latch.await();
            }
            //前一个节点不存在,则当前节点可获取锁
            lockedBy = currentNode;
        } catch (InterruptedException e) {
            logger.error("thread is interrupted{}", e);
        } catch (KeeperException e) {
            logger.error("KeeperException{}", e);
            e.printStackTrace();
        }
    }

    @Override
    public boolean tryLock() {
        if(hasLocked()) {
            return true;
        }

        try {
            if (null == currentNode) {
                currentNode = zooKeeper.create(LOCK_ROOT + nodeName, Thread.currentThread().getName().getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
                logger.info("线程{}创建节点{}完成", Thread.currentThread().getName(), currentNode);
            }
            //如果当前最小的节点与当前创建的节点相同,则获取到锁
            if(isLockNode(currentNode)) {
                return true;
            }
        } catch (InterruptedException e) {
            logger.error("create zooKeeper node failed...", e);
            e.printStackTrace();
        } catch (KeeperException e) {
            logger.error("create zooKeeper node failed...", e);
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    /**
     * 判断当前节点是否是需要枷锁的节点(最小的节点)
     * @param currentNode
     * @return
     */
    private boolean isLockNode(String currentNode) {
        List<String> nodes = getChildren();
        Collections.sort(nodes, new Comparator<String>() {
            public int compare(String s1, String s2) {
                return s1.compareTo(s2);
            }
        });

        lockedBy = LOCK_ROOT + "/" + nodes.get(0);

        if(currentNode.equals(lockedBy)) {
            return true;
        }

        //需要监控前一个节点数据的变化
        String nodeName = currentNode.substring(LOCK_ROOT.length() + 1);
        for(int i = 1; i < nodes.size(); i++) {
            if(nodeName.equals(nodes.get(i))) {
                prevNode = LOCK_ROOT + "/" + nodes.get(i - 1);
                break;
            }
        }
        return false;
    }

    /**
     * 获取所有节点
     * @return
     */
    private List<String> getChildren() {
        try {
            return zooKeeper.getChildren(LOCK_ROOT, false);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断当前是否已经获取到锁
     * @return
     */
    private boolean hasLocked() {
        return null != currentNode && null != lockedBy && currentNode.equals(lockedBy);
    }

    @Override
    public void unlock() {
        try {
            Stat stat = zooKeeper.exists(currentNode, true);
            if(null != stat) {
                logger.info("线程{}释放锁{}", Thread.currentThread().getName(), currentNode);
                zooKeeper.delete(currentNode, stat.getVersion());
            }
        } catch (KeeperException e) {
            e.printStackTrace();
            logger.info("线程{}释放锁{}失败", Thread.currentThread().getName(), currentNode);
        } catch (InterruptedException e) {
            e.printStackTrace();
            logger.info("线程{}释放锁{}失败", Thread.currentThread().getName(), currentNode);
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public Condition newCondition() {
        return null;
    }


    /**
     * 监控节点变化
     */
    private class ZKWatcher implements Watcher {
        @Override
        public void process(WatchedEvent event) {
            //判断是否是删除节点事件,并且判断删除的节点是否是当前节点的前一个节点
            if(event.getType() == Event.EventType.NodeDeleted) {
                latch.countDown();
            }
        }
    }
}


你可能感兴趣的:(基于zookeeper的分布式锁)