zoukankan      html  css  js  c++  java
  • zookeeper 分布式锁

    1,为什么需要分布式锁

    在分布式集群环境中,多个程序同时在跑,就存在多个线程对同一个资源的共享并且操作问题。因此会存在线程安全问题。

    2,在单个JVM 程序中,存在线程安全问题的时候,我们一般可以用synchronized 同步代码块,或者使用Lock 锁等方式,使得在多线程环境下,同一时刻只能由一个线程去操作共享资源。

    3,在分布式多个JVM 环境中,我们一般使用分布式锁,使得在同一时刻,只能由集群中的某一台JVM 服务获取到锁,同时有操作的权力,其他JVM 服务只能等锁释放之后,再次去获取锁,获得锁的服务才能去操作。

    4,zookeeper 如何实现分布式锁

    zookeeper 的数据结构中,节点Znode的类型可以分为:临时(ephemeral)和  永久(persistent)。

    通过zookeeper 实现分布式锁,主要是通过临时节点来实现。临时节点的生命周期是一个连接会话,即客户端连接zookeeper服务器,创建了临时节点,当连接中断,则这个节点就会被删除。同时zookeeper的节点名称只能唯一。

    所以实现思路:

    集群的JVM同时创建一个临时节点,创建成功的JVM 获得锁,操作业务逻辑,操纵完成,释放锁

    package com.zklock;
    
    public interface Lock {
    
        public void lock();
    
        public void unlock();
    
    }
    package com.zklock;
    
    import org.I0Itec.zkclient.ZkClient;
    
    public abstract class ZookeeperAbstractLock implements Lock {
    
        // zk连接地址
        private static final String CONNECTSTRING = "127.0.0.1:2181";
        // 创建zk连接,protected 让子类去实现
        protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
        // 分布式锁的临时节点,protected 让子类去实现
        protected static final String PATH = "/lock";
    
        // 获取锁
        public void lock() {
            if (getLock()) {
                // 获取到了锁
                System.out.println("######获取锁成功######");
            } else {
                // 没有获取到锁的JVM 进行等待
                waitLock();
                // 等拥有锁的JVM释放之后,继续获取锁
                lock();
            }
    
        }
    
        abstract void waitLock();
    
        
        abstract boolean getLock();
    
        // 释放锁
        public void unlock() {
            if (zkClient != null) {
                zkClient.close();
                System.out.println("######锁已经释放######");
            }
        }
    
    }

    具体实现

    package com.zklock;
    
    import java.util.concurrent.CountDownLatch;
    
    import org.I0Itec.zkclient.IZkDataListener;
    
    public class ZookeeperLock extends ZookeeperAbstractLock {
    
        private CountDownLatch countDownLatch = null;
    
        @Override
        void waitLock() {
    
            // zookeeper 数据监听的接口
            IZkDataListener izkDataListener = new IZkDataListener() {
                public void handleDataChange(String arg0, Object arg1) throws Exception {
    
                }
    
                public void handleDataDeleted(String path) throws Exception {
                    // 一直在监听,节点有变化的时候原子量就是-1
                    if (countDownLatch != null) {
    
                        countDownLatch.countDown();
                    }
                }
    
            };
            // 已经有JVM 获取到锁,现在需要等待锁释放,所以zkClient会去监听
            zkClient.subscribeDataChanges(PATH, izkDataListener);
            if (zkClient.exists(PATH)) {
                countDownLatch = new CountDownLatch(1);
                try {
                    // 一直进行等待,等待监听的路径有变化
                    countDownLatch.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            // 删除监听
            zkClient.unsubscribeDataChanges(PATH, izkDataListener);
    
        }
    
        @Override
        boolean getLock() {
            // 获取锁
            if (zkClient != null) {
                try {
                    zkClient.createEphemeral(PATH);
                    return true;
                } catch (Exception e) {
                    System.out.println(e);
                    System.out.println("#####创建临时节点失败####");
                    return false;
                }
            }
            return false;
        }
    }

    测试:

    package com.zklock;
    
    
    public class Test implements Runnable{
        
        ZookeeperLock zookeeperLock  = new ZookeeperLock();
        
        public static void main(String[] args) {
            for(int i = 0; i < 50; i++){
                Test test = new Test();
                new Thread(test).start();
            }
        }
    
        public void run() {
            try {
                zookeeperLock.lock();
                System.out.println("id= "+System.currentTimeMillis());
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                zookeeperLock.unlock();
            }
        }
    
    }
  • 相关阅读:
    Two strings CodeForces
    Dasha and Photos CodeForces
    Largest Beautiful Number CodeForces
    Timetable CodeForces
    Financiers Game CodeForces
    AC日记——整理药名 openjudge 1.7 15
    AC日记——大小写字母互换 openjudge 1.7 14
    AC日记——将字符串中的小写字母换成大写字母 openjudge 1.7 13
    AC日记——加密的病历单 openjudge 1.7 12
    AC日记——潜伏着 openjudge 1.7 11
  • 原文地址:https://www.cnblogs.com/pickKnow/p/11338579.html
Copyright © 2011-2022 走看看