关于zookeeper的一二三·再续

前面的两篇已经对ZK有了一些介绍(传送门:关于zookeeper的一二三关于zookeeper的一二三·续),今天继续来探讨一个典型的应用场景:分布式共享锁。

1、需求
在我们自己的分布式业务系统中,可能会存在某种资源,需要被整个系统的各台服务器共享访问,但是只允许一台服务器同时访问,此时,我们需要设计一个分布式共享锁。
设计思路:
这里写图片描述

package zklock;

import org.apache.zookeeper.*;

import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * Created by Cage on 2016/10/17.
 */
public class DistributeClientLock {
    //会话超时
    private static final int SESSION_TIMEOUT = 2000;
    private static final String CONNECT_STRING = "had01:2181,had02:2181,had03:2181";
    private String groupNode = "locks";
    private String subNode = "sub";
    private boolean  haveLock = false;
    private ZooKeeper zk;
    //记录自己创建的子节点路径
    private volatile String thisPath;


    /**
     * 连接zookeeper
     */
    public void connectZookeeper() throws Exception {
        zk = new ZooKeeper(CONNECT_STRING, SESSION_TIMEOUT, new Watcher() {
            public void process(WatchedEvent event) {
                try {

                    // 判断事件类型,此处只处理子节点变化事件
                    if (event.getType() == Watcher.Event.EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {
                        //获取子节点,并对父节点进行监听
                        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);
                        String thisNode = thisPath.substring(("/" + groupNode + "/").length());
                        // 去比较是否自己是最小id
                        Collections.sort(childrenNodes);
                        if (childrenNodes.indexOf(thisNode) == 0) {
                            //访问共享资源处理业务,并且在处理完成之后删除锁
                            doSomething();

                            //重新注册一把新的锁
                            thisPath = zk.create("/" + groupNode + "/" + subNode, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                                    CreateMode.EPHEMERAL_SEQUENTIAL);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        // 1、程序一进来就先注册一把锁到zk上
        thisPath = zk.create("/" + groupNode + "/" + subNode, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);

        // wait一小会,便于观察
        Thread.sleep(new Random().nextInt(1000));

        // 从zk的锁父目录下,获取所有子节点,并且注册对父节点的监听
        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

        // 如果争抢资源的程序就只有自己,则可以直接去访问共享资源
        if (childrenNodes.size() == 1) {
            doSomething();
            thisPath = zk.create("/" + groupNode + "/" + subNode, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
        }
    }

    /**
     * 处理业务逻辑,并且在最后释放锁
     */
    private void doSomething() throws Exception {
        try {
            System.out.println("gain lock: " + thisPath);
            Thread.sleep(2000);
            // do something
        } finally {
            System.out.println("finished: " + thisPath);
            //
            // 访问完毕后,需要手动去删除之前的锁节点
            zk.delete(this.thisPath, -1);
        }
    }

    public static void main(String[] args) throws Exception {
        DistributeClientLock dl = new DistributeClientLock();
        dl.connectZookeeper();
        Thread.sleep(Long.MAX_VALUE);
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值