zookeeper实现分布式锁

        分布式锁主要解决多个进程访问同一资源时的资源竞争问题。主要有三种解决方案,基于数据库实现分布式锁,基于缓存实现分布式锁和基于zookeeper实现分布式锁。

一、三种实现方案介绍

1、基于数据库实现分布式锁

        基于数据库实现分布式锁实现起来比较简单,但是其有如下缺点:

        (1)性能较差,容易出现单点故障,此由数据库连接池的连接数决定的;

        (2)锁没有失效时间,容易死锁,经常出现的情况是线程死了,数据库记录没有删除,导致出现死锁;

        (3)非阻塞式。

2、基于缓存实现分布式锁

        基于缓存实现分布式锁原理和基于数据库类似,其性能和并发量相较于数据库实现要大大提升,但是也会有如下缺点:

        (1)需要为锁设置失效时间,但是失效时间无法准确设定。

3、基于zookeeper实现分布式锁

        基于zookeeper相较于前面两种方案,其性能和可靠性都有所提升,也是最长采用的方案,其特点如下:

        (1)实现简单;

        (2)可靠性好;

        (3)性能好。

二、zookeeper简介

        zookeeper是一个分布式的、开放源代码的分布式应用程序协调服务,是Hadoop和Hbase的重要组件。在zk中zNode是一个跟Unix或者Windows文件系统路径相似的节点,可以往这个节点存储或者获取数据。

        通过客户端可以对zNode进行增删改查操作,还可以注册watcher监控zNode的变化。zNode跟文件系统一样,名称不可重复。

        zk的节点类型包括:持久节点,持久顺序节点,临时节点,临时顺序节点。临时节点跟会话有关,连接断掉,节点会被自动删除。

三、基于zookeeper实现分布式锁的代码示例

1、定义Lock接口

public interface Lock {

        public void lock();

        public void unLock();

}

2、Lock抽象类(模板模式)     

public abstract class AbstractLock implements Lock{ 

         protected static String host = "127.0.0.1";

         protected static int port = 2181; 

         protected static String path = "/lock"; 

         protected static ZkClient zkClient = new ZkClient(host, port);

         @Override 

         public void lock() { 

             if(tryLock()){

                    System.out.println("获取锁成功!!!");              

             }else{                  

                     //如果尝试获取锁失败,则等待获取锁                 

                     waitForLock();                  

                     lock();              

             } 

        }

         protected abstract boolean tryLock(); 

         protected abstract void waitForLock(); 

 } 

3、锁的具体实现类

public class ZookeeperLock extends AbstractLock{

        private CountDownLatch cdl =null;

        /**

        * 解锁即删除临时节点

        */

        @Override

        public void unLock() {

                zkClient.delete(path);

        }

        /**

        * 如果创建临时节点成表示获取锁成功

        */

        @Override

        protected boolean tryLock() {

            try{

                zkClient.createEphemeral(path);

                return true;

            }catch(Exception e){

                return false ;

            }

        }

        @Override

        protected void waitForLock() {

                IZkDataListener listener = new IZkDataListener(){

                        @Override

                        public void handleDataChange(String dataPath, Object data) throws Exception {

                        }

                        @Override

                        public void handleDataDeleted(String dataPath) throws Exception {

                                //监听临时节点删除事件

                                if(cdl!=null){

                                    cdl.countDown();

                                }

                        }

            };

            //订阅节点改变事件

           zkClient.subscribeDataChanges(path, listener);

           if(zkClient.exists(path)){

                //线程在此阻塞,直到临时节点删除事件触发

                cdl = new CountDownLatch(1);

                try {

                         cdl.await();

                } catch (InterruptedException e) {

                         // TODO Auto-generated catch block

                         e.printStackTrace();

                }

           }

            zkClient.unsubscribeDataChanges(path, listener);

        }

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 第一创建一个http请求(新建主题),在http请求方法处选择:POST,具体如下图 创建一个post请求编辑主题
    红叶_aec0阅读 976评论 0 0
  • 孩子做作业认真自觉了很多,还记得刚上一年级时做一次作业那么费劲,我的脾气也是暴躁,经常性的呕吼,还好,孩子没受到太...
    母师征程阅读 122评论 0 0
  • 1.下载和打开官方文档的步骤(1).在code->preferences->components(目录下的docu...
    zhaihongxia阅读 581评论 0 0
  • 关于git换行符处理的问题,我查了一查,自己的设置中,global-config中设了autocrlf=false...
    乖乖果效36阅读 1,311评论 0 0