zookeeper深入学习(3)---简单分布式共享锁的实现

本文介绍两种基于Zookeeper的分布式锁实现方案:多线程模拟实现与多进程模式实现。通过创建临时有序节点,利用Zookeeper的特性确保同一时刻只有一个客户端能够获取锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、多线程的模拟实现:

package DistributedLock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 分布式共享锁的简单实现
 * Created by tianjun on 2016/12/19 0019.
 */
public class DistributedClient {
    //超时时间
    private static final int SESSION_TIMEOUT=5000;
    //zk 列表
    private String hosts = "mini04:2181,mini05:2181,mini06:2181";
    private String groupNode = "locks";
    private String subNode = "sub";

    private ZooKeeper zk = null;
    //当前client创建的子节点
    private String thisPath = null;
    //当前client等待的子节点
    private String waitPath = null;

    private CountDownLatch latch = new CountDownLatch(1);

    public void connnectZookeeper() throws IOException, KeeperException, InterruptedException {

        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {

            public void process(WatchedEvent event) {

                //连接建立时,打开latch,唤醒wait在该latch上的线程
                if(event.getState() == Event.KeeperState.SyncConnected){
                    latch.countDown();
                }
                //发生了waitPath的删除事件
                if(event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)){
                    try {
                        doSomething();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        //等待建立链接
        latch.await();

        //创建子节点
        thisPath = zk.create("/"+groupNode+"/"+subNode,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

        //wait一小会儿
        Thread.sleep(10);

        //注意,没有必要监听"/locks"的子节点的变化情况
        List<String> childrenNodes = zk.getChildren("/"+groupNode,false);

        //列表中只有一个子节点,那肯定就是thisPath,说明client获得锁
        if(childrenNodes.size() == 1){
            doSomething();
        }else{
            String thisNode = thisPath.substring(("/"+groupNode+"/").length());
            Collections.sort(childrenNodes);
            int index = childrenNodes.indexOf(thisNode);
            if(index==-1){
                //never happned
            }else if(index == 0){
                //index==0,说明thisNode在列表中最小,当前client获得锁
                doSomething();
            }else{
                //获得排名比thisPath前1位的节点
                this.waitPath = "/"+groupNode+"/"+childrenNodes.get(index - 1);

                //在waitPath上注册监听器,当waitPath被删除时,zookeeper会回调监听器的process方法
                zk.getData(waitPath,true,new Stat());
            }
        }
    }

    private void doSomething() throws InterruptedException, KeeperException {
        try {
            System.out.println("gain lock:"+thisPath);
            Thread.sleep(2000);
            //do something
        } finally {
            System.out.println("finished:"+this.thisPath);
            //将thisPath删除,监听thisPath的client将获得通知
            //相当于释放锁
            zk.delete(this.thisPath,-1);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for(int i =0 ; i < 10 ; i++){
            new Thread(){

                public void run(){
                    try {
                        DistributedClient d1 = new DistributedClient();
                        d1.connnectZookeeper();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }.start();
        }

        Thread.sleep(Long.MAX_VALUE);
    }

}

2、分布式多进程模式实现

package DistributedLock;

import org.apache.zookeeper.*;

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

/**
 *  分布式共享锁的简单实现(多进程模式实现)
 * Created by tianjun on 2016/12/19 0019.
 */
public class DistributedClientMy {
    //超时时间
    private static final int SESSION_TIMEOUT=5000;
    //zk 列表
    private String hosts = "mini04:2181,mini05:2181,mini06:2181";
    private String groupNode = "locks";
    private String subNode = "sub";
    private boolean haveLock = false;

    private ZooKeeper zk = null;

    // 当前client创建的子节点
    private volatile String thisPath;

    /**
     * 连接zookeeper
     */
    public void connectZookeeper() throws Exception {

        zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {

            public void process(WatchedEvent event) {
                try {

                    // 子节点发生变化
                    if (event.getType() == Event.EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {
                        // thisPath是否是列表中的最小节点
                        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);
                        String thisNode = thisPath.substring(("/" + groupNode + "/").length());
                        // 排序
                        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();
                }

            }
        });


        // 创建子节点
        thisPath = zk.create("/" + groupNode + "/" + subNode, null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);

        // wait一小会, 让结果更清晰一些
        Thread.sleep(new Random().nextInt(1000));

        // 监听子节点的变化
        List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

        // 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁
        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);
            // 将thisPath删除, 监听thisPath的client将获得通知
            // 相当于释放锁
            zk.delete(this.thisPath, -1);
        }
    }

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




}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值