zoukankan      html  css  js  c++  java
  • Zk原生分布式锁

    一、主要需要解决的问题
        1、加锁
             创建临时带有顺序的节点,如果是第一个则,获取锁成功
        2、解锁
            删除自己创建的临时节点
        3、死锁问题
            临时节点,如果客户端down机了,则节点监听自动删除
        4、锁等待与唤醒
            每个等待的线程等待上一个节点删除,一旦删除,则自己被唤醒去获取锁
     
    使用模板设计模式进行处理
    二、锁接口
    public interface Lock {
        //获取到锁的资源
        public void getLock();
        // 释放锁
        public void unLock();
    }

     三、抽象锁

    public abstract class AbstractLock  implements  Lock{
    
    
        public void getLock() {
            //任务通过竞争获取锁才能对该资源进行操作(①竞争锁);
            // 当有一个任务在对资源进行更新时(②占有锁),
            // 其他任务都不可以对这个资源进行操作(③任务阻塞),
            // 直到该任务完成更新(④释放锁)
            //尝试获得锁资源
            //①竞争锁
            if (tryLock()) {
                System.out.println("##获取lock锁的资源####");
            } else {
                //③任务阻塞
                waitLock();
                // 重新获取锁资源
                getLock();
            }
        }
        // ②占有锁
        public abstract boolean tryLock();
        // 等待
        public abstract void waitLock();
    }

    四、抽象锁的公共参数

    public abstract class ZookeeperAbstractLock extends AbstractLock {
        // zk连接地址
        private static final String CONNECTSTRING = "127.0.0.1:2181";
        // 创建zk连接
        protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
        protected static final String PATH = "/lock";
        protected static final String PATH2 = "/lock2";
    
    }

    五、具体实现

    public class ZookeeperDistrbuteLock2 extends ZookeeperAbstractLock {
        private CountDownLatch countDownLatch= null;
    
    
        private String beforePath;//当前请求的节点前一个节点
        private String currentPath;//当前请求的节点
    
        public ZookeeperDistrbuteLock2() {
            if (!this.zkClient.exists(PATH2)) {
                this.zkClient.createPersistent(PATH2);
            }
        }
    
        @Override
        public boolean  tryLock() {
            //如果currentPath为空则为第一次尝试加锁,第一次加锁赋值currentPath
            if(currentPath == null || currentPath.length()<= 0){
                //创建一个临时顺序节点
                currentPath = this.zkClient.createEphemeralSequential(PATH2 + '/',"lock");
            }
            //获取所有临时节点并排序,临时节点名称为自增长的字符串如:0000000400
            List<String> childrens = this.zkClient.getChildren(PATH2);
            Collections.sort(childrens);
    
            if (currentPath.equals(PATH2 + '/'+childrens.get(0))) {//如果当前节点在所有节点中排名第一则获取锁成功
                return true;
            } else {//如果当前节点在所有节点中排名中不是排名第一,则获取前面的节点名称,并赋值给beforePath
                int wz = Collections.binarySearch(childrens,
                        currentPath.substring(7));
                beforePath = PATH2 + '/'+childrens.get(wz-1);
            }
            return false;
        }
    
        @Override
        public void waitLock() {
            IZkDataListener listener = new IZkDataListener() {
    
    
                public void handleDataDeleted(String dataPath) throws Exception {
                    if(countDownLatch!=null){
                        countDownLatch.countDown();
                    }
                }
                public void handleDataChange(String dataPath, Object data) throws Exception {
                }
            };
            //给排在前面的的节点增加数据删除的watcher,本质是启动另外一个线程去监听前置节点
            this.zkClient.subscribeDataChanges(beforePath, listener);
            if(this.zkClient.exists(beforePath)){
                countDownLatch=new CountDownLatch(1);
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.zkClient.unsubscribeDataChanges(beforePath, listener);
        }
    
        public void unLock() {
            //删除当前临时节点
            zkClient.delete(currentPath);
            zkClient.close();
        }
    }
     
     
     
     
  • 相关阅读:
    89组合margin、padding、float、clear问题
    absoulue与relative配合定位盒子居中问题
    11种常用css样式之表格和定位样式学习
    11种常用css样式之鼠标、列表和尺寸样式学习
    C++走向远洋——54(项目一2、分数类的重载、取倒数)
    C++走向远洋——53(项目一1、分数类的重载、加减乘除、比较)
    HTML标签学习总结(1)
    9——PHP循环结构foreach用法
    C++走向远洋——52(十三周阅读程序)
    我为什么要用CSDN博客?
  • 原文地址:https://www.cnblogs.com/lean-blog/p/14150540.html
Copyright © 2011-2022 走看看