zoukankan      html  css  js  c++  java
  • 使用Zookeeper实现分布式锁

    利用Zookeeper临时节点(客户端异常断开连接后临时节点自动移除)或者Redis SETNX(set if not exists)(设置ttl)可以实现分布式锁,这里先利用zk实现一个

    1.启动zk

    2.代码实现

       2.1 Maven引入zk & zk client

      

      2.2 代码和注释

    import org.I0Itec.zkclient.ZkClient;
    
    import java.util.concurrent.CountDownLatch;
    
    public class ZKDistributeLockTest {
    
        public static void main(String[] args) {
            // 使用CountDownLunch控制线程同时执行
            CountDownLatch countDownLatch = new CountDownLatch(1);
            // 开启3个线程模拟分布式环境,分布式环境下每个进程都是一个单独的zkClient
            Thread t1 = new Thread(new TestThread(countDownLatch));
            Thread t2 = new Thread(new TestThread(countDownLatch));
            Thread t3 = new Thread(new TestThread(countDownLatch));
            t1.start();
            t2.start();
            t3.start();
    
            System.out.println("休眠1秒后执行..." + System.currentTimeMillis());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 倒计时结束
            countDownLatch.countDown();
        }
    
    
    }
    
    // 线程,尝试在zk上创建临时节点,创建成功则获得锁(执行权)
    class TestThread implements Runnable {
        // 共享变量
        private static Integer CNT = 0;
        private ZkClient zkClient;
        private CountDownLatch countDownLatch;
        public TestThread(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }
    
        // 连接zk
        private void connect() {
            String threadName = Thread.currentThread().getName();
            try {
                System.out.println(threadName + " 等待执行...");
                // 等待倒计时结束
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(threadName + " 请求连接zk..." + System.currentTimeMillis());
            zkClient = new ZkClient("192.168.1.217:2181", 20000);
            System.out.println(threadName + " 连接成功...");
            // 输出目录信息测试
    //        List<String> children = zkClient.getChildren("/");
    //        children.forEach(System.out::println);
        }
    
        @Override
        public void run() {
            // 初始化连接(在各个线程里开启连接,模拟分布式环境)
            connect();
            String threadName = Thread.currentThread().getName();
    
            // 竞争锁
            while (true) {
                try {
                    System.out.println(threadName + " 开始竞争锁...");
                    // 创建zk临时节点
                    zkClient.createEphemeral("/dl", "test");
                    System.out.println(threadName + " 获得锁!!!");
                    // 获得锁后修改共享变量
                    CNT ++;
                    System.out.println(threadName + " 释放了锁..." + CNT);
                    zkClient.delete("/dl");
                    Thread.sleep(2000);
                } catch (Exception e) {
                    // 创建临时节点失败,表示未获得锁
                    System.out.println(threadName + " 未获得锁,将重试!!!");
    //                System.out.println(e.getMessage());
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }
    

      

    3.测试结果

    4.Zookeeper如何保证分布式环境下的线程安全(不重复创建节点)?

    查看zookeeper源码发现,创建节点是同步方法

    而写请求(创建节点)都是在master节点执行,而创建节点又做了同步控制,所以即使是分布式环境创建节点也是线程安全的。

  • 相关阅读:
    396 Rotate Function 旋转函数
    395 Longest Substring with At Least K Repeating Characters 至少有K个重复字符的最长子串
    394 Decode String 字符串解码
    393 UTF-8 Validation UTF-8 编码验证
    392 Is Subsequence 判断子序列
    391 Perfect Rectangle 完美矩形
    390 Elimination Game 淘汰游戏
    389 Find the Difference 找不同
    388 Longest Absolute File Path 最长的绝对文件路径
    387 First Unique Character in a String 字符串中的第一个唯一字符
  • 原文地址:https://www.cnblogs.com/zhya/p/11211458.html
Copyright © 2011-2022 走看看