zookeeper分布式锁案例

zookeeper分布式锁案例

文档

  1. linux安装java -centos安装java -linux配置java环境变量
  2. zookeeper单机安装
  3. zookeeper集群安装
  4. zookeeper客户端命令行操作、节点类型及监听器
  5. zookeeper集群写数据原理
  6. java操作zookeeper

手写分布式锁案例

原理

  1. 线程获取锁时,在/locks节点下创建临时有序号节点,需要注意的是,有序号的节点序号是递增的

    create -e -s /locks/seq-
    

    同时获取/locks节点的子节点列表,并对子节点列表进行排序,并获取当前节点的索引

  2. 如果当前节点是索引最小的节点,直接返回,表示获取到锁

  3. 如果当前节点不是索引最小的节点,设置监听,监听前一个索引节点的值的变化,同时线程等待

  4. 实际上,以上两步已经将获取锁的顺序设置好了

  5. 获取到锁的线程执行完之后,删除节点,表示释放锁。此时将触发下一个节点的监听回调,唤醒等待的线程

  6. 重复步骤5,直到所有的锁都释放

java代码实现分布式锁

  1. 分布式锁示例代码DistributedLock.java

    package xin.yangshuai.zookeeper01.case2;
    
    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;
    
    public class DistributedLock {
    
        // 注意:逗号左右不能有空格
        private String connectString = "192.168.145.132:2181,192.168.145.133:2181,192.168.145.134:2181";
        // 2000毫秒
        private int sessionTimeout = 2000;
    
        private ZooKeeper zkClient;
    
        private CountDownLatch countDownLatch = new CountDownLatch(1);
    
        private CountDownLatch waitLatch = new CountDownLatch(1);
    
        private String currentMode;
        private String listeningNode;
    
        public DistributedLock() throws IOException, InterruptedException, KeeperException {
    
            // 获取连接
            zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {
                @Override
                public void process(WatchedEvent watchedEvent) {
                    // 初始化时,会执行一次
                    System.out.println(watchedEvent.getPath() + "----------------------------");
    
                    // 启动时会触发,表示已经连接上zookeeper了,放行
                    if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                        countDownLatch.countDown();
                    }
    
                    // 触发监听,监听的节点被删除了,放行
                    if (watchedEvent.getType() == Event.EventType.NodeDeleted && watchedEvent.getPath().equals(listeningNode)) {
                        waitLatch.countDown();
                    }
                }
            });
    
            countDownLatch.await();
            // 已经连接上zookeeper后,继续执行
    
            // 判断父节点/locks是否存在
            Stat stat = zkClient.exists("/locks", false);
            if (stat == null) {
                // 创建父节点/locks
                zkClient.create("/locks", "locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        }
    
        // 获取锁
        public void lock() throws KeeperException, InterruptedException {
    
            // 创建临时有序号节点
            currentMode = zkClient.create("/locks/seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
    
            Thread.sleep(10);
    
            // 获取/locks节点的子节点列表
            List<String> children = zkClient.getChildren("/locks", false);
    
            if (children.size() == 1) {
                // 只有一个节点,直接获取锁,返回
                return;
            }
    
            Collections.sort(children);
    
            // 获取节点名称,seq-00000000
            String thisNode = currentMode.substring("/locks/".length());
            // 获取节点在集合中的位置
            int index = children.indexOf(thisNode);
    
            if (index == 0) {
                // 是第一个节点,直接获取锁,返回
                return;
            }
    
            // 获取前一个索引的节点
            listeningNode = "/locks/" + children.get(index - 1);
            // 监听前一个节点的值的变化
            zkClient.getData(listeningNode, true, null);
    
            // 线程等待,直到上一个节点释放锁(被删除)时,将触发监听回调,会设置此处放行
            System.out.println(Thread.currentThread().getName() + " 未获取到锁,等待");
            waitLatch.await();
            // 上一个节点释放锁,继续执行,表示获取到锁
        }
    
        // 解锁
        public void unlock() throws KeeperException, InterruptedException {
    
            // 删除节点,表示释放锁
            zkClient.delete(currentMode, -1);
        }
    }
    
  2. 测试方法示例代码DistributedLockTest.java

    package xin.yangshuai.zookeeper01.case2;
    
    import org.apache.zookeeper.KeeperException;
    
    import java.io.IOException;
    
    public class DistributedLockTest {
    
        public static void main(String[] args) throws InterruptedException, IOException, KeeperException {
    
            DistributedLock lock1 = new DistributedLock();
    
            DistributedLock lock2 = new DistributedLock();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock1.lock();
                        System.out.println(Thread.currentThread().getName() + " 获取到锁");
    
                        Thread.sleep(5000);
    
                        lock1.unlock();
    
                        System.out.println(Thread.currentThread().getName() + " 释放锁");
                    } catch (KeeperException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "线程1").start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock2.lock();
                        System.out.println(Thread.currentThread().getName() + " 获取到锁");
    
                        Thread.sleep(5000);
    
                        lock2.unlock();
    
                        System.out.println(Thread.currentThread().getName() + " 释放锁");
                    } catch (KeeperException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "线程2").start();
        }
    }
    
  3. 仅供参考

Curator框架实现分布式锁案例

官网地址:https://curator.apache.org/docs/about

java代码示例

  1. 测试方法示例代码CuratorLockTest.java

    package xin.yangshuai.zookeeper01.case3;
    
    import org.apache.curator.framework.CuratorFramework;
    import org.apache.curator.framework.CuratorFrameworkFactory;
    import org.apache.curator.framework.recipes.locks.InterProcessMutex;
    import org.apache.curator.retry.ExponentialBackoffRetry;
    
    public class CuratorLockTest {
    
        // 注意:逗号左右不能有空格
        private static String connectString = "192.168.145.132:2181,192.168.145.133:2181,192.168.145.134:2181";
        // 2000毫秒
        private static int sessionTimeout = 2000;
    
        public static void main(String[] args) {
    
            // 创建分布式锁1
            InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework(), "/locks");
    
            // 创建分布式锁2
            InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework(), "/locks");
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock1.acquire();
                        System.out.println("线程1 获取到锁");
    
                        lock1.acquire();
                        System.out.println("线程1 再次获取到锁");
    
                        Thread.sleep(5000);
    
                        lock1.release();
                        System.out.println("线程1 释放锁");
    
                        lock1.release();
                        System.out.println("线程1 再次释放锁");
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock2.acquire();
                        System.out.println("线程2 获取到锁");
    
                        lock2.acquire();
                        System.out.println("线程2 再次获取到锁");
    
                        Thread.sleep(5000);
    
                        lock2.release();
                        System.out.println("线程2 释放锁");
    
                        lock2.release();
                        System.out.println("线程2 再次释放锁");
    
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    
        // 连接zookeeper
        private static CuratorFramework getCuratorFramework() {
    
            ExponentialBackoffRetry policy = new ExponentialBackoffRetry(3000, 3);
    
            CuratorFramework client = CuratorFrameworkFactory.builder()
                    .connectString(connectString)
                    .connectionTimeoutMs(sessionTimeout)
                    .sessionTimeoutMs(sessionTimeout)
                    .retryPolicy(policy).build();
    
            // 启动客户端
            client.start();
    
            System.out.println("zookeeper客户端启动成功");
            return client;
        }
    }
    
  2. 仅供参考

参考资料

  • 尚硅谷

你可能感兴趣的:(zookeeper,分布式,zookeeper,云原生)