ZK 分布式锁

通俗的解释:类似与生活中的排队,所有人都向前一个人看(前面有没有人,他在未获得锁之前有有没走,走了就在向前看一个,一直观察这个,直至得到锁),如果自己的前面没有人,那么自己是第一个(获得锁),获得锁的人,事没做完,锁是不会被解开的,其他人只能等待,直至结束,锁解开,下一个人获得锁

百度了张图(侵权请告知)

 

 

public class runTest {
    static int TASK_SUM_COUNTS=10;
    static CountDownLatch threadLatch = new CountDownLatch(TASK_SUM_COUNTS);

    public static void main(String a[]) throws Exception {
        //运行10个线程,模拟10人排队
        for (int i = 0; i < TASK_SUM_COUNTS; i++) {
            new Thread(new Runnable() {
                public void run() {
                    try {
                        new MyThread(new Doing() {
                            public void todo() {
                                System.out.println("----要做的事");
                                //处理完一个人的,count减1
                                threadLatch.countDown();
                            }
                        });
                    } catch (Exception e) {
                        System.out.println("--发生了错误");
                    }
                }
            }).start();
        }
        //等待10个线程运行完毕(count直至到0,程序才会向下执行,否则在此等待)
        threadLatch.await();
        System.out.println("----所有任务执行完毕!");
    }
}

 

public class MyThread extends UnicastRemoteObject implements Watcher {


    private String PUB_PATH = "/Dis";
    private String SUB_PATH = PUB_PATH + "/task";
    private String url = "localhost:11102";
    private CountDownLatch zkLatch;
    private ZooKeeper zooKeeper;
    private Doing doing;
    //单个文件名     文件名是:task0001、task0002.....
    private String dirS;

    public MyThread(Doing doing) throws Exception {
        this.doing = doing;
        zkLatch = new CountDownLatch(1);
        zooKeeper = new ZooKeeper(url, 2000, this);
        //等待连上ZK
        zkLatch.await();
        getLock();
    }

    //创建节点并分配锁
    private void getLock() throws KeeperException, InterruptedException {
        if (zooKeeper.exists(PUB_PATH, false) == null) {
            //如果目录不存在,创建目录
            zooKeeper.create(PUB_PATH, "存储队列目录".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        //创建序列化的短期文件
        dirS = zooKeeper.create(SUB_PATH, "这里是内容,根据业务填,不填传null".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        if (checkFirst()) {
            //获取锁
            doing.todo();
        }
    }

    //检测我是否可以拿到锁
    private boolean checkFirst() throws KeeperException, InterruptedException {
        List<String> children = zooKeeper.getChildren(PUB_PATH, true);
        //排序
        Collections.sort(children);
        //判断该文件在集合中的第几位
        int index = children.indexOf(dirS.substring(PUB_PATH.length() + 1));
        switch (index) {
            case -1:
                System.out.println("----该文件已不存在了");
                return false;
            case 0:
                System.out.println("----我是第一位,我可以拿到锁");
                return true;
            default:
                //观察前一位
                try {
                    //这里的try catch是为了在getData时,文件不存在会抛出异常,如果文件不存在,那么就观察再前一位,这里采用递归查找
                    String watcherFile = PUB_PATH + children.get(index - 1);
                    System.out.println("-----给我之前的文件:" + watcherFile + "  增加Watcher观察");
                    zooKeeper.getData(watcherFile, this, new Stat());
                    return false;
                } catch (Exception e) {
                    System.out.println("----前面那位居然失踪了。。。我再向前看一位。。哈哈哈");
                    return checkFirst();
                }

        }
    }

    public void process(WatchedEvent event) {
        if (event.getState() == Event.KeeperState.SyncConnected) {
            //连上了ZK,count减1,使程序继续运行
            zkLatch.countDown();
        }
    }

 

posted @ 2018-03-06 16:39  猴子1  阅读(148)  评论(0编辑  收藏  举报