一,阻塞式和非阻塞式

“阻塞”和“非阻塞”只是一个人为的概念,“阻塞”说的是一个线程去尝试获取锁,如果失败,就阻塞在这里,监听到持有锁的线程释放,再次去尝试获取。 而“非阻塞”是我尝试一次失败了,失败就拉倒,直接不要了。

而这两个区别是通过代码来体现的。

二,zk非阻塞式锁的实现

(1)首先定义“锁”的接口,包括上锁,解锁,锁是否存在。

public interface ZkLocker {
    /**
     * 能否上锁成功
     */
    boolean lock();
    /**
     * 解锁 能否解锁成功
     */
    boolean unlock();
    /**
     * 判断锁是否存在
     */
    boolean exists();
}

(2)定义基类,包含对于zookeeper结点的一些基本操作,包括和zk连接,创建结点,删除结点...等等。所有的锁(不管什么锁都要继承这个类)

public class ZkLockerBase {
    //客户端和服务端连接
    protected ZooKeeper zooKeeper;
    //锁的根节点的名称
    protected String rootNodeName = "/zk-lock";
    //锁的名称
    protected String lockName;

    /**
     * 默认连接到指定的服务端
     * @throws IOException
     * @throws InterruptedException
     */
    public ZkLockerBase() {
        this("localhost:2181");//服务器ip地址,改。
    }

    public ZkLockerBase(String connectString){
        try {
            CountDownLatch latch = new CountDownLatch(1);
            zooKeeper = new ZooKeeper(connectString, 5000000, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    switch (event.getType()) {
                        case None:
                            if (event.getState().equals(Event.KeeperState.SyncConnected)) {
                                latch.countDown();
                            }
                            break;
                        case NodeCreated:
                            break;
                        case NodeDeleted:
                            break;
                        case NodeChildrenChanged:
                            break;
                    }
                }
            });
            latch.await();
            createRootNode();//连接之后创建根节点
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 创建根节点,用于存放所有的节点或者子节点实现的锁
     */
    public void createRootNode(){
        //判断我的root是否存在
        if (!exists(rootNodeName)){
            createNode(rootNodeName,CreateMode.CONTAINER);
        }
    }
    public boolean exists(String nodeName){
        try {
            Stat exists = zooKeeper.exists(nodeName, false);
            return exists != null;
        }catch (Exception e){

        }
        return false;
    }
    /**
     * return真正的名字
     * @param nodeName 创建结点名字
     * @param createMode 创建结点的类型
     * @return 创建成功之后结点的名字
     */
    public String createNode(String nodeName, CreateMode createMode) {
        try {
            return zooKeeper.create(nodeName, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, createMode);
        }catch (Exception e){
            e.printStackTrace();
            return null;//创建失败
        }
    }

    /**
     * 删除结点
     * @param nodeName
     * @return
     */
    public boolean deleteNode(String nodeName){
        try {
            zooKeeper.delete(nodeName,-1);//跳过版本检查
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
}

(3)zk非阻塞式锁实现

public class ZkNodeNoneBlockingLock extends ZkLockerBase implements ZkLocker {
    /**
     * 默认连接
     * @param lockName
     */
    public ZkNodeNoneBlockingLock(String lockName){
        super();
        this.lockName = lockName;
    }

    /**
     * 可指定连接
     * @param connectString
     * @param lockName
     */
    public ZkNodeNoneBlockingLock(String connectString,String lockName){
        super(connectString);
        this.lockName = lockName;
    }
    @Override
    public boolean lock() {
        return createNode(rootNodeName + "/" + lockName,
                CreateMode.EPHEMERAL) != null;
    }

    @Override
    public boolean unlock() {
        return deleteNode(rootNodeName + "/" + lockName);
    }

    @Override
    public boolean exists() {
        return exists(rootNodeName + "/" + lockName);
    }
}

接下来跑测试代码来测试,分别测试在单线程和多线程并发状态下的结果。

测试代码:

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部