ZooKeeper连接并创建节点以及实现分布式锁操作节点排序输出最小节点Demo

class LockThread implements Runnable {
    private DistributedLock lock;
    

    public LockThread(int threadId,CountDownLatch latch) throws Exception {
        this.lock = new DistributedLock(threadId,latch);
    }

    @Override
    public void run() {
        //每一个线程对象启动后都应该创建一个临时的节点信息
        try {
            this.lock.handle();//进行具体的操作处理
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class TestDistributedLock {

    public static void main(String[] args) throws Exception {
        CountDownLatch latch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
                new Thread(new LockThread(i,latch)).start();;
        }
        //Thread.sleep(Long.MAX_VALUE);//为了保证可以观察到所有的临时节点信息,保证此处先不进行关闭
        latch.await();
        System.out.println("************* 所有的线程对象操作完毕  *************");
    }
public class DistributedLock {//建立一个描述分布式锁的程序处理类
    public static final String CONNECTION_RUL = "192.168.12.121:2181,192.168.12.122:2181";

    public static final int SESSION_TIMEOUT = 2000;//设置连接超时时间

    public static final String AUTH_INFO = "zkuser:mldnjava";//进行连接的授权信息

    public static final String GROUPNODE = "/mldn-lock";//根节点

    public static final String SUNBODE = GROUPNODE + "/lockthread-";//子节点

    private CountDownLatch latch = null;

    //本操作的主要目的是为了在取得zookeeper连接之后才能进行后续的处理
    private CountDownLatch connectLatch = new CountDownLatch(1);

    private ZooKeeper zkClient = null; //建立Zookeeper程序控制类

    private String selfPath; //保存每次创建的临时节点信息

    private String waitPath; //保存下一个要进行处理的节点

    private int threadId = 0;

    /** 进行一些初始化操作使用
     * 
     * @param threadId 随意给定一个编号信息 * @param latch 进行线程同步处理
     * @throws Exception */
    public DistributedLock(int threadId, CountDownLatch latch) throws Exception {
        this.threadId = threadId;//保存每一个线程对象自己的ID信息
        this.latch = latch;
        this.connectionZookeeper();//进行节点的连接
    }

    public void handle() throws Exception {//具体业务处理
        this.createSubNode();//创建临时节点操作
    }

    public void handleSuccess() throws Exception {//表示取得锁之后进行的处理
        if (this.zkClient.exists(this.selfPath, false) == null) {
            return;//如果当前节点不存在
        }
        this.handleCallback();//执行具体的业务操作
        //如果某一个节点操作完毕了,那么应该立即删除掉该节点,否则获得的最小节点永远都是该节点
        this.zkClient.delete(selfPath, -1);
        this.releaseZookeeper();//释放连接
        this.latch.countDown();//进行减减的操作
    }

    public void handleCallback() throws Exception {//取得分布式锁之后的目的是要进行具体的操作
        Thread.sleep(200);//实现一个延迟处理
        System.out
                .println("****** Thread-" + this.threadId + "获得操作权,进行具体的业务操作");
    }

    public boolean checkMinPath() throws Exception {//进行最小节点的判断
        List<String> childen = this.zkClient.getChildren(GROUPNODE, false);//取得所有的节点信息
        Collections.sort(childen); //进行所有节点的排序,这样最小的节点就拍到最上面
        int index = childen
                .indexOf(this.selfPath.substring(GROUPNODE.length() + 1));
        switch (index) {
            case 0: {
                return true; //已经确定好当前的节点为最小节点
            }
            case -1: {
                return false; //该节点可能已经消失了
            }
            default: {//表示该节点不属于最小节点,那么应该向后继续排查
                this.waitPath = GROUPNODE + "/" + childen.get(index - 1);//获得下一个节点
                try {
                    this.zkClient.getData(waitPath, true, new Stat());//取得下一个节点的数据
                    return false; //本节点不是当前的操作的最小节点
                } catch (Exception e) {//如果出现了异常,则表示该节点不存在
                    if (this.zkClient.exists(waitPath, false) == null) {
                        return this.checkMinPath();//继续向后检测
                    } else {
                        throw e;
                    }
                }
            }
        }
    }

    public void createSubNode() throws Exception {//每一个线程对象的启动都要求创建一个节点信息
        this.zkClient.create(SUNBODE, ("Thread-" + this.threadId).getBytes(),
                ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println("【Thread-" + this.threadId + "、创建新的临时节点】"
                + this.selfPath);
        //当节点创建完成之后就需要进行最小节点的检测
        if (this.checkMinPath()) {//如果当前的节点为整个项目的最小节点
            this.handleSuccess();//进行锁后的具体操作
        }
    }

    public void connectionZookeeper() throws Exception {//连接zookeeper服务
        this.zkClient = new ZooKeeper(CONNECTION_RUL, SESSION_TIMEOUT,
                new Watcher() {

                    @Override
                    public void process(WatchedEvent event) {
                        if (event.getType() == EventType.None) {//第一次连接zookeeper的时候会出现none
                            DistributedLock.this.connectLatch.countDown();//表示已经连接成功
                        } else { //要处理删除节点操作,并且要确定下一个节点是已经准备出来的节点信息
                            if (event.getType() == EventType.NodeDeleted
                                    && event.getPath().equals(
                                            DistributedLock.this.waitPath)) {
                                try {
                                    if (DistributedLock.this.checkMinPath()) {//如果当前的节点为整个项目的最小节点
                                        DistributedLock.this.handleSuccess();//进行锁后的具体操作
                                    }
                                } catch (Exception e) {
                                        e.printStackTrace();
                                }
                            }
                        }
                    }
                });
        this.zkClient.addAuthInfo("digest", AUTH_INFO.getBytes());//进行授权认证
        if (this.zkClient.exists(GROUPNODE, false) == null) {
            this.zkClient.create(GROUPNODE, "LOCKDEMO".getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        this.connectLatch.await();//等待连接后才执行后续的功能
    }

    public void releaseZookeeper() {//进行zookeeper的连接释放
        if (this.zkClient != null) {
            try {
                this.zkClient.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

 

posted @ 2018-09-28 17:47  Fire飞扬跋扈  阅读(299)  评论(0编辑  收藏  举报