编程之路
首发于编程之路
分布式学习(2) ---- Zookeeper实现分布式锁

分布式学习(2) ---- Zookeeper实现分布式锁

分布式锁有三中实现方式:Zookeeper、Memcached、Redis 。

本文先用Zookeeper实现一下

方式1:利用名称唯一性

谁能创建某名称节点,谁就获得锁。

但释放锁时会出现惊群效应,被PASS

方式2:利用临时顺序节点

画了个思维导图如下:

利用Zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,创建的节点都是有顺序的,每次选择最小编号的节点获得锁。当前节点watcher上一个节点,当上一个节点被删除时,因为是临时节点,也就是上一个节点与zookeeper断开连接时,当前节点成为最小节点,从而获得锁。

关键代码:

//检查当前节点是否为最小节点
public boolean checkMinPath() throws KeeperException, InterruptedException {
        //获取锁节点下所有待争夺节点
        List<String> subNodes = zk.getChildren(GROUP_PATH, false);
        //对所有节点排序
        Collections.sort(subNodes);
        //判断此节点在所有节点中的位置
        int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
        switch (index){
            case -1:{
                System.out.println(PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
                return false;
            }
            case 0:{
                System.out.println(PREFIX_OF_THREAD+"子节点中,我最小,可以获得锁了!哈哈"+selfPath);
                return true;
            }
            default:{
                this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
                System.out.println(PREFIX_OF_THREAD+"排在我前面的节点是 "+waitPath);
                try{
                    zk.getData(waitPath, true, new Stat());
                    return false;
                }catch(KeeperException e){
                    if(zk.exists(waitPath,false) == null){
                        System.out.println(PREFIX_OF_THREAD+"排在我前面的"+waitPath+"已消失 ");
                        return checkMinPath();
                    }else{
                        throw e;
                    }
                }
            }
        }
    }

测试:开了10个线程,创建一个持久的锁节点,再创建10个临时节点,按编号顺序依次获取锁节点。日志如下:

【第3个线程】成功连接上ZK服务器
【第10个线程】成功连接上ZK服务器
【第1个线程】成功连接上ZK服务器
【第6个线程】成功连接上ZK服务器
【第5个线程】成功连接上ZK服务器
【第9个线程】成功连接上ZK服务器
【第2个线程】成功连接上ZK服务器
【第4个线程】成功连接上ZK服务器
【第7个线程】成功连接上ZK服务器
【第8个线程】成功连接上ZK服务器
【第10个线程】节点创建成功, Path: /lock, content: 该节点由线程10创建
【第10个线程】创建锁路径:/lock/sub0000000000
【第10个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000000
【第8个线程】创建锁路径:/lock/sub0000000001
【第10个线程】获取锁成功,开始干活!
【第8个线程】排在我前面的节点是 /lock/sub0000000000
【第7个线程】创建锁路径:/lock/sub0000000002
【第7个线程】排在我前面的节点是 /lock/sub0000000001
【第4个线程】创建锁路径:/lock/sub0000000003
【第2个线程】创建锁路径:/lock/sub0000000004
【第4个线程】排在我前面的节点是 /lock/sub0000000002
【第2个线程】排在我前面的节点是 /lock/sub0000000003
【第3个线程】创建锁路径:/lock/sub0000000005
【第9个线程】创建锁路径:/lock/sub0000000006
【第3个线程】排在我前面的节点是 /lock/sub0000000004
【第9个线程】排在我前面的节点是 /lock/sub0000000005
【第5个线程】创建锁路径:/lock/sub0000000007
【第5个线程】排在我前面的节点是 /lock/sub0000000006
【第6个线程】创建锁路径:/lock/sub0000000008
【第6个线程】排在我前面的节点是 /lock/sub0000000007
【第1个线程】创建锁路径:/lock/sub0000000009
【第1个线程】排在我前面的节点是 /lock/sub0000000008
【第8个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第10个线程】工作完毕,释放锁
【第8个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000001
【第8个线程】获取锁成功,开始干活!
【第7个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第8个线程】工作完毕,释放锁
【第7个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000002
【第7个线程】获取锁成功,开始干活!
【第4个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第7个线程】工作完毕,释放锁
【第4个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000003
【第4个线程】获取锁成功,开始干活!
【第2个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第4个线程】工作完毕,释放锁
【第2个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000004
【第2个线程】获取锁成功,开始干活!
【第3个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第2个线程】工作完毕,释放锁
【第3个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000005
【第3个线程】获取锁成功,开始干活!
【第3个线程】工作完毕,释放锁
【第9个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第9个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000006
【第9个线程】获取锁成功,开始干活!
【第5个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第9个线程】工作完毕,释放锁
【第5个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000007
【第5个线程】获取锁成功,开始干活!
【第6个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第5个线程】工作完毕,释放锁
【第6个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000008
【第6个线程】获取锁成功,开始干活!
【第1个线程】watch说我前面那个节点要挂了,我可以获取锁啦!!
【第6个线程】工作完毕,释放锁
【第1个线程】子节点中,我最小,可以获得锁了!哈哈/lock/sub0000000009
【第1个线程】获取锁成功,开始干活!
【第1个线程】工作完毕,释放锁
所有线程运行结束!

源码:Java分布式学习 ---- zookeeper实现DistributedLock

编辑于 2017-02-07

文章被以下专栏收录