• 基于zookeeper简单实现分布式锁


    https://blog.csdn.net/desilting/article/details/41280869

    这里利用zookeeper的EPHEMERAL_SEQUENTIAL类型节点及watcher机制,来简单实现分布式锁。

    主要思想:
    1、开启10个线程,在disLocks节点下各自创建名为sub的EPHEMERAL_SEQUENTIAL节点;
    2、获取disLocks节点下所有子节点,排序,如果自己的节点编号最小,则获取锁;
    3、否则watch排在自己前面的节点,监听到其删除后,进入第2步(重新检测排序是防止监听的节点发生连接失效,导致的节点删除情况);
    4、删除自身sub节点,释放连接;
     
    这里插播下zookeeper的4种节点类型:
    1. public enum CreateMode {  
    2.      
    3.     /** 
    4.      * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除; 
    5.      */  
    6.     PERSISTENT (0, false, false),  
    7.   
    8.     /** 
    9.     * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;  
    10.     */  
    11.     PERSISTENT_SEQUENTIAL (2, false, true),  
    12.   
    13.     /** 
    14.      *  临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException; 
    15.      */  
    16.     EPHEMERAL (1, true, false),  
    17.   
    18.     /** 
    19.      * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名;  
    20.      */  
    21.     EPHEMERAL_SEQUENTIAL (3, true, true);  
    22.     private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);  
    23.     private boolean ephemeral;  
    24.     private boolean sequential;  
    25.     private int flag;  
    26.     CreateMode(int flag, boolean ephemeral, boolean sequential) {  
    27.         this.flag = flag;  
    28.         this.ephemeral = ephemeral;  
    29.         this.sequential = sequential;  
    30.     }  
    31.     public boolean isEphemeral() {  
    32.         return ephemeral;  
    33.     }  
    34.     public boolean isSequential() {  
    35.         return sequential;  
    36.     }  
    37.     public int toFlag() {  
    38.         return flag;  
    39.     }  
    40.     static public CreateMode fromFlag(int flag) throws KeeperException {  
    41.         switch(flag) {  
    42.         case 0: return CreateMode.PERSISTENT;  
    43.         case 1: return CreateMode.EPHEMERAL;  
    44.         case 2: return CreateMode.PERSISTENT_SEQUENTIAL;  
    45.         case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;  
    46.         default:  
    47.             LOG.error("Received an invalid flag value to convert to a CreateMode");  
    48.             throw new KeeperException.BadArgumentsException();  
    49.         }  
    50.     }  
    51. }  
    public enum CreateMode {
       
        /**
         * 持久节点:节点创建后,会一直存在,不会因客户端会话失效而删除;
         */
        PERSISTENT (0, false, false),
    
        /**
        * 持久顺序节点:基本特性与持久节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名; 
        */
        PERSISTENT_SEQUENTIAL (2, false, true),
    
        /**
         *  临时节点:客户端会话失效或连接关闭后,该节点会被自动删除,且不能再临时节点下面创建子节点,否则报如下错:org.apache.zookeeper.KeeperException$NoChildrenForEphemeralsException;
         */
        EPHEMERAL (1, true, false),
    
        /**
         * 临时顺序节点:基本特性与临时节点一致,创建节点的过程中,zookeeper会在其名字后自动追加一个单调增长的数字后缀,作为新的节点名; 
         */
        EPHEMERAL_SEQUENTIAL (3, true, true);
        private static final Logger LOG = LoggerFactory.getLogger(CreateMode.class);
        private boolean ephemeral;
        private boolean sequential;
        private int flag;
        CreateMode(int flag, boolean ephemeral, boolean sequential) {
            this.flag = flag;
            this.ephemeral = ephemeral;
            this.sequential = sequential;
        }
        public boolean isEphemeral() {
            return ephemeral;
        }
        public boolean isSequential() {
            return sequential;
        }
        public int toFlag() {
            return flag;
        }
        static public CreateMode fromFlag(int flag) throws KeeperException {
            switch(flag) {
            case 0: return CreateMode.PERSISTENT;
            case 1: return CreateMode.EPHEMERAL;
            case 2: return CreateMode.PERSISTENT_SEQUENTIAL;
            case 3: return CreateMode.EPHEMERAL_SEQUENTIAL ;
            default:
                LOG.error("Received an invalid flag value to convert to a CreateMode");
                throw new KeeperException.BadArgumentsException();
            }
        }
    }


    测试代码:
    1. package zookeeper;  
    2. import org.slf4j.Logger;  
    3. import org.slf4j.LoggerFactory;  
    4. import org.apache.zookeeper.*;  
    5. import org.apache.zookeeper.data.Stat;  
    6. import java.util.List;  
    7. import java.io.IOException;  
    8. import java.util.Collections;  
    9. import java.util.concurrent.CountDownLatch;  
    10.   
    11. public class DistributedLock implements Watcher{  
    12.     private int threadId;  
    13.     private ZooKeeper zk = null;  
    14.     private String selfPath;  
    15.     private String waitPath;  
    16.     private String LOG_PREFIX_OF_THREAD;  
    17.     private static final int SESSION_TIMEOUT = 10000;  
    18.     private static final String GROUP_PATH = "/disLocks";  
    19.     private static final String SUB_PATH = "/disLocks/sub";  
    20.     private static final String CONNECTION_STRING = "192.168.*.*:2181";  
    21.       
    22.     private static final int THREAD_NUM = 10;   
    23.     //确保连接zk成功;  
    24.     private CountDownLatch connectedSemaphore = new CountDownLatch(1);  
    25.     //确保所有线程运行结束;  
    26.     private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);  
    27.     private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);  
    28.     public DistributedLock(int id) {  
    29.         this.threadId = id;  
    30.         LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";  
    31.     }  
    32.     public static void main(String[] args) {  
    33.         for(int i=0; i < THREAD_NUM; i++){  
    34.             final int threadId = i+1;  
    35.             new Thread(){  
    36.                 @Override  
    37.                 public void run() {  
    38.                     try{  
    39.                         DistributedLock dc = new DistributedLock(threadId);  
    40.                         dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);  
    41.                         //GROUP_PATH不存在的话,由一个线程创建即可;  
    42.                         synchronized (threadSemaphore){  
    43.                             dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);  
    44.                         }  
    45.                         dc.getLock();  
    46.                     } catch (Exception e){  
    47.                         LOG.error("【第"+threadId+"个线程】 抛出的异常:");  
    48.                         e.printStackTrace();  
    49.                     }  
    50.                 }  
    51.             }.start();  
    52.         }  
    53.         try {  
    54.             threadSemaphore.await();  
    55.             LOG.info("所有线程运行结束!");  
    56.         } catch (InterruptedException e) {  
    57.             e.printStackTrace();  
    58.         }  
    59.     }  
    60.     /** 
    61.      * 获取锁 
    62.      * @return 
    63.      */  
    64.     private void getLock() throws KeeperException, InterruptedException {  
    65.         selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);  
    66.         LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);  
    67.         if(checkMinPath()){  
    68.             getLockSuccess();  
    69.         }  
    70.     }  
    71.     /** 
    72.      * 创建节点 
    73.      * @param path 节点path 
    74.      * @param data 初始数据内容 
    75.      * @return 
    76.      */  
    77.     public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {  
    78.         if(zk.exists(path, needWatch)==null){  
    79.             LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "  
    80.                     + this.zk.create( path,  
    81.                     data.getBytes(),  
    82.                     ZooDefs.Ids.OPEN_ACL_UNSAFE,  
    83.                     CreateMode.PERSISTENT )  
    84.                     + ", content: " + data );  
    85.         }  
    86.         return true;  
    87.     }  
    88.     /** 
    89.      * 创建ZK连接 
    90.      * @param connectString  ZK服务器地址列表 
    91.      * @param sessionTimeout Session超时时间 
    92.      */  
    93.     public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {  
    94.             zk = new ZooKeeper( connectString, sessionTimeout, this);  
    95.             connectedSemaphore.await();  
    96.     }  
    97.     /** 
    98.      * 获取锁成功 
    99.     */  
    100.     public void getLockSuccess() throws KeeperException, InterruptedException {  
    101.         if(zk.exists(this.selfPath,false) == null){  
    102.             LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");  
    103.             return;  
    104.         }  
    105.         LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");  
    106.         Thread.sleep(2000);  
    107.         LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);  
    108.         zk.delete(this.selfPath, -1);  
    109.         releaseConnection();  
    110.         threadSemaphore.countDown();  
    111.     }  
    112.     /** 
    113.      * 关闭ZK连接 
    114.      */  
    115.     public void releaseConnection() {  
    116.         if ( this.zk !=null ) {  
    117.             try {  
    118.                 this.zk.close();  
    119.             } catch ( InterruptedException e ) {}  
    120.         }  
    121.         LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");  
    122.     }  
    123.     /** 
    124.      * 检查自己是不是最小的节点 
    125.      * @return 
    126.      */  
    127.     public boolean checkMinPath() throws KeeperException, InterruptedException {  
    128.          List<String> subNodes = zk.getChildren(GROUP_PATH, false);  
    129.          Collections.sort(subNodes);  
    130.          int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));  
    131.          switch (index){  
    132.              case -1:{  
    133.                  LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);  
    134.                  return false;  
    135.              }  
    136.              case 0:{  
    137.                  LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);  
    138.                  return true;  
    139.              }  
    140.              default:{  
    141.                  this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);  
    142.                  LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);  
    143.                  try{  
    144.                      zk.getData(waitPath, true, new Stat());  
    145.                      return false;  
    146.                  }catch(KeeperException e){  
    147.                      if(zk.exists(waitPath,false) == null){  
    148.                          LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");  
    149.                          return checkMinPath();  
    150.                      }else{  
    151.                          throw e;  
    152.                      }  
    153.                  }  
    154.              }  
    155.                    
    156.          }  
    157.        
    158.     }  
    159.     @Override  
    160.     public void process(WatchedEvent event) {  
    161.         if(event == null){  
    162.             return;  
    163.         }  
    164.         Event.KeeperState keeperState = event.getState();  
    165.         Event.EventType eventType = event.getType();  
    166.         if ( Event.KeeperState.SyncConnected == keeperState) {  
    167.             if ( Event.EventType.None == eventType ) {  
    168.                 LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );  
    169.                 connectedSemaphore.countDown();  
    170.             }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {  
    171.                 LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");  
    172.                 try {  
    173.                     if(checkMinPath()){  
    174.                         getLockSuccess();  
    175.                     }  
    176.                 } catch (KeeperException e) {  
    177.                     e.printStackTrace();  
    178.                 } catch (InterruptedException e) {  
    179.                     e.printStackTrace();  
    180.                 }  
    181.             }  
    182.         }else if ( Event.KeeperState.Disconnected == keeperState ) {  
    183.             LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );  
    184.         } else if ( Event.KeeperState.AuthFailed == keeperState ) {  
    185.             LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );  
    186.         } else if ( Event.KeeperState.Expired == keeperState ) {  
    187.             LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );  
    188.         }  
    189.     }  
    190. }  
    package zookeeper;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.apache.zookeeper.*;
    import org.apache.zookeeper.data.Stat;
    import java.util.List;
    import java.io.IOException;
    import java.util.Collections;
    import java.util.concurrent.CountDownLatch;
    
    public class DistributedLock implements Watcher{
        private int threadId;
        private ZooKeeper zk = null;
        private String selfPath;
        private String waitPath;
        private String LOG_PREFIX_OF_THREAD;
        private static final int SESSION_TIMEOUT = 10000;
        private static final String GROUP_PATH = "/disLocks";
        private static final String SUB_PATH = "/disLocks/sub";
        private static final String CONNECTION_STRING = "192.168.*.*:2181";
        
        private static final int THREAD_NUM = 10; 
        //确保连接zk成功;
        private CountDownLatch connectedSemaphore = new CountDownLatch(1);
        //确保所有线程运行结束;
        private static final CountDownLatch threadSemaphore = new CountDownLatch(THREAD_NUM);
        private static final Logger LOG = LoggerFactory.getLogger(AllZooKeeperWatcher.class);
        public DistributedLock(int id) {
            this.threadId = id;
            LOG_PREFIX_OF_THREAD = "【第"+threadId+"个线程】";
        }
        public static void main(String[] args) {
            for(int i=0; i < THREAD_NUM; i++){
                final int threadId = i+1;
                new Thread(){
                    @Override
                    public void run() {
                        try{
                            DistributedLock dc = new DistributedLock(threadId);
                            dc.createConnection(CONNECTION_STRING, SESSION_TIMEOUT);
                            //GROUP_PATH不存在的话,由一个线程创建即可;
                            synchronized (threadSemaphore){
                                dc.createPath(GROUP_PATH, "该节点由线程" + threadId + "创建", true);
                            }
                            dc.getLock();
                        } catch (Exception e){
                            LOG.error("【第"+threadId+"个线程】 抛出的异常:");
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
            try {
                threadSemaphore.await();
                LOG.info("所有线程运行结束!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        /**
         * 获取锁
         * @return
         */
        private void getLock() throws KeeperException, InterruptedException {
            selfPath = zk.create(SUB_PATH,null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            LOG.info(LOG_PREFIX_OF_THREAD+"创建锁路径:"+selfPath);
            if(checkMinPath()){
                getLockSuccess();
            }
        }
        /**
         * 创建节点
         * @param path 节点path
         * @param data 初始数据内容
         * @return
         */
        public boolean createPath( String path, String data, boolean needWatch) throws KeeperException, InterruptedException {
            if(zk.exists(path, needWatch)==null){
                LOG.info( LOG_PREFIX_OF_THREAD + "节点创建成功, Path: "
                        + this.zk.create( path,
                        data.getBytes(),
                        ZooDefs.Ids.OPEN_ACL_UNSAFE,
                        CreateMode.PERSISTENT )
                        + ", content: " + data );
            }
            return true;
        }
        /**
         * 创建ZK连接
         * @param connectString	 ZK服务器地址列表
         * @param sessionTimeout Session超时时间
         */
        public void createConnection( String connectString, int sessionTimeout ) throws IOException, InterruptedException {
                zk = new ZooKeeper( connectString, sessionTimeout, this);
                connectedSemaphore.await();
        }
        /**
         * 获取锁成功
        */
        public void getLockSuccess() throws KeeperException, InterruptedException {
            if(zk.exists(this.selfPath,false) == null){
                LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了...");
                return;
            }
            LOG.info(LOG_PREFIX_OF_THREAD + "获取锁成功,赶紧干活!");
            Thread.sleep(2000);
            LOG.info(LOG_PREFIX_OF_THREAD + "删除本节点:"+selfPath);
            zk.delete(this.selfPath, -1);
            releaseConnection();
            threadSemaphore.countDown();
        }
        /**
         * 关闭ZK连接
         */
        public void releaseConnection() {
            if ( this.zk !=null ) {
                try {
                    this.zk.close();
                } catch ( InterruptedException e ) {}
            }
            LOG.info(LOG_PREFIX_OF_THREAD + "释放连接");
        }
        /**
         * 检查自己是不是最小的节点
         * @return
         */
        public boolean checkMinPath() throws KeeperException, InterruptedException {
             List<String> subNodes = zk.getChildren(GROUP_PATH, false);
             Collections.sort(subNodes);
             int index = subNodes.indexOf( selfPath.substring(GROUP_PATH.length()+1));
             switch (index){
                 case -1:{
                     LOG.error(LOG_PREFIX_OF_THREAD+"本节点已不在了..."+selfPath);
                     return false;
                 }
                 case 0:{
                     LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,我果然是老大"+selfPath);
                     return true;
                 }
                 default:{
                     this.waitPath = GROUP_PATH +"/"+ subNodes.get(index - 1);
                     LOG.info(LOG_PREFIX_OF_THREAD+"获取子节点中,排在我前面的"+waitPath);
                     try{
                         zk.getData(waitPath, true, new Stat());
                         return false;
                     }catch(KeeperException e){
                         if(zk.exists(waitPath,false) == null){
                             LOG.info(LOG_PREFIX_OF_THREAD+"子节点中,排在我前面的"+waitPath+"已失踪,幸福来得太突然?");
                             return checkMinPath();
                         }else{
                             throw e;
                         }
                     }
                 }
                     
             }
         
        }
        @Override
        public void process(WatchedEvent event) {
            if(event == null){
                return;
            }
            Event.KeeperState keeperState = event.getState();
            Event.EventType eventType = event.getType();
            if ( Event.KeeperState.SyncConnected == keeperState) {
                if ( Event.EventType.None == eventType ) {
                    LOG.info( LOG_PREFIX_OF_THREAD + "成功连接上ZK服务器" );
                    connectedSemaphore.countDown();
                }else if (event.getType() == Event.EventType.NodeDeleted && event.getPath().equals(waitPath)) {
                    LOG.info(LOG_PREFIX_OF_THREAD + "收到情报,排我前面的家伙已挂,我是不是可以出山了?");
                    try {
                        if(checkMinPath()){
                            getLockSuccess();
                        }
                    } catch (KeeperException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }else if ( Event.KeeperState.Disconnected == keeperState ) {
                LOG.info( LOG_PREFIX_OF_THREAD + "与ZK服务器断开连接" );
            } else if ( Event.KeeperState.AuthFailed == keeperState ) {
                LOG.info( LOG_PREFIX_OF_THREAD + "权限检查失败" );
            } else if ( Event.KeeperState.Expired == keeperState ) {
                LOG.info( LOG_PREFIX_OF_THREAD + "会话失效" );
            }
        }
    }
    
    

    log配置文件:
    1. # DEFAULT   
    2. log4j.rootLogger=INFO,CONSOLE  
    3.   
    4. #  
    5. # Log INFO level and above messages to the console  
    6. #  
    7. log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender  
    8. log4j.appender.CONSOLE.Threshold=INFO  
    9. log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout  
    10. log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n  
    11.   
    12.   
    13. log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender  
    14. log4j.appender.COMMONSTAT.Threshold=INFO  
    15. log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log  
    16. log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd  
    17.   
    18. log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout  
    19. log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n  
    20.   
    21. log4j.logger.org.displaytag=WARN  
    22. log4j.logger.org.apache.zookeeper=ERROR  
    23. log4j.logger.org.springframework=WARN  
    24. log4j.logger.org.I0Itec=WARN  
    25. log4j.logger.commonStat=INFO,COMMONSTAT  
    # DEFAULT 
    log4j.rootLogger=INFO,CONSOLE
    
    #
    # Log INFO level and above messages to the console
    #
    log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
    log4j.appender.CONSOLE.Threshold=INFO
    log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
    log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %m%n
    
    
    log4j.appender.COMMONSTAT=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.COMMONSTAT.Threshold=INFO
    log4j.appender.COMMONSTAT.File=/home/zookeeper/zookeeper-test-agent/logs/test.log
    log4j.appender.COMMONSTAT.DatePattern='.'yyyy-MM-dd
    
    log4j.appender.COMMONSTAT.layout=org.apache.log4j.PatternLayout
    log4j.appender.COMMONSTAT.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}] - %m%n
    
    log4j.logger.org.displaytag=WARN
    log4j.logger.org.apache.zookeeper=ERROR
    log4j.logger.org.springframework=WARN
    log4j.logger.org.I0Itec=WARN
    log4j.logger.commonStat=INFO,COMMONSTAT

    运行结果:
    1. 2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器  
    2. 2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器  
    3. 2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器  
    4. 2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器  
    5. 2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器  
    6. 2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器  
    7. 2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器  
    8. 2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器  
    9. 2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器  
    10. 2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器  
    11. 2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建  
    12. 2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000  
    13. 2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001  
    14. 2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000  
    15. 2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002  
    16. 2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000  
    17. 2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!  
    18. 2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003  
    19. 2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001  
    20. 2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002  
    21. 2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004  
    22. 2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005  
    23. 2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003  
    24. 2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006  
    25. 2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004  
    26. 2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007  
    27. 2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005  
    28. 2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008  
    29. 2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006  
    30. 2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009  
    31. 2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007  
    32. 2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008  
    33. 2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000  
    34. 2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    35. 2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001  
    36. 2014-11-19 11:34:12,930 - 【第9个线程】释放连接  
    37. 2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!  
    38. 2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001  
    39. 2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    40. 2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002  
    41. 2014-11-19 11:34:14,943 - 【第6个线程】释放连接  
    42. 2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!  
    43. 2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002  
    44. 2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    45. 2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003  
    46. 2014-11-19 11:34:16,953 - 【第3个线程】释放连接  
    47. 2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!  
    48. 2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003  
    49. 2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    50. 2014-11-19 11:34:18,960 - 【第10个线程】释放连接  
    51. 2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004  
    52. 2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!  
    53. 2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004  
    54. 2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    55. 2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005  
    56. 2014-11-19 11:34:20,971 - 【第1个线程】释放连接  
    57. 2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!  
    58. 2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005  
    59. 2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    60. 2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006  
    61. 2014-11-19 11:34:22,979 - 【第5个线程】释放连接  
    62. 2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!  
    63. 2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006  
    64. 2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    65. 2014-11-19 11:34:24,989 - 【第2个线程】释放连接  
    66. 2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007  
    67. 2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!  
    68. 2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007  
    69. 2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    70. 2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008  
    71. 2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!  
    72. 2014-11-19 11:34:27,004 - 【第4个线程】释放连接  
    73. 2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008  
    74. 2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?  
    75. 2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009  
    76. 2014-11-19 11:34:29,010 - 【第8个线程】释放连接  
    77. 2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!  
    78. 2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009  
    79. 2014-11-19 11:34:31,017 - 【第7个线程】释放连接  
    80. 2014-11-19 11:34:31,017 - 所有线程运行结束!  
    2014-11-19 11:34:10,894 - 【第9个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,895 - 【第8个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,894 - 【第1个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,894 - 【第7个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,894 - 【第4个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,895 - 【第5个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,896 - 【第2个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,894 - 【第10个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,894 - 【第3个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,895 - 【第6个线程】成功连接上ZK服务器
    2014-11-19 11:34:10,910 - 【第9个线程】节点创建成功, Path: /disLocks, content: 该节点由线程9创建
    2014-11-19 11:34:10,912 - 【第9个线程】创建锁路径:/disLocks/sub0000000000
    2014-11-19 11:34:10,917 - 【第6个线程】创建锁路径:/disLocks/sub0000000001
    2014-11-19 11:34:10,917 - 【第9个线程】子节点中,我果然是老大/disLocks/sub0000000000
    2014-11-19 11:34:10,921 - 【第3个线程】创建锁路径:/disLocks/sub0000000002
    2014-11-19 11:34:10,922 - 【第6个线程】获取子节点中,排在我前面的/disLocks/sub0000000000
    2014-11-19 11:34:10,923 - 【第9个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:10,924 - 【第10个线程】创建锁路径:/disLocks/sub0000000003
    2014-11-19 11:34:10,924 - 【第3个线程】获取子节点中,排在我前面的/disLocks/sub0000000001
    2014-11-19 11:34:10,928 - 【第10个线程】获取子节点中,排在我前面的/disLocks/sub0000000002
    2014-11-19 11:34:10,929 - 【第1个线程】创建锁路径:/disLocks/sub0000000004
    2014-11-19 11:34:10,932 - 【第5个线程】创建锁路径:/disLocks/sub0000000005
    2014-11-19 11:34:10,935 - 【第1个线程】获取子节点中,排在我前面的/disLocks/sub0000000003
    2014-11-19 11:34:10,936 - 【第2个线程】创建锁路径:/disLocks/sub0000000006
    2014-11-19 11:34:10,936 - 【第5个线程】获取子节点中,排在我前面的/disLocks/sub0000000004
    2014-11-19 11:34:10,940 - 【第4个线程】创建锁路径:/disLocks/sub0000000007
    2014-11-19 11:34:10,941 - 【第2个线程】获取子节点中,排在我前面的/disLocks/sub0000000005
    2014-11-19 11:34:10,943 - 【第8个线程】创建锁路径:/disLocks/sub0000000008
    2014-11-19 11:34:10,944 - 【第4个线程】获取子节点中,排在我前面的/disLocks/sub0000000006
    2014-11-19 11:34:10,945 - 【第7个线程】创建锁路径:/disLocks/sub0000000009
    2014-11-19 11:34:10,946 - 【第8个线程】获取子节点中,排在我前面的/disLocks/sub0000000007
    2014-11-19 11:34:10,947 - 【第7个线程】获取子节点中,排在我前面的/disLocks/sub0000000008
    2014-11-19 11:34:12,923 - 【第9个线程】删除本节点:/disLocks/sub0000000000
    2014-11-19 11:34:12,926 - 【第6个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:12,928 - 【第6个线程】子节点中,我果然是老大/disLocks/sub0000000001
    2014-11-19 11:34:12,930 - 【第9个线程】释放连接
    2014-11-19 11:34:12,930 - 【第6个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:14,930 - 【第6个线程】删除本节点:/disLocks/sub0000000001
    2014-11-19 11:34:14,937 - 【第3个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:14,941 - 【第3个线程】子节点中,我果然是老大/disLocks/sub0000000002
    2014-11-19 11:34:14,943 - 【第6个线程】释放连接
    2014-11-19 11:34:14,946 - 【第3个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:16,946 - 【第3个线程】删除本节点:/disLocks/sub0000000002
    2014-11-19 11:34:16,949 - 【第10个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:16,951 - 【第10个线程】子节点中,我果然是老大/disLocks/sub0000000003
    2014-11-19 11:34:16,953 - 【第3个线程】释放连接
    2014-11-19 11:34:16,953 - 【第10个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:18,953 - 【第10个线程】删除本节点:/disLocks/sub0000000003
    2014-11-19 11:34:18,957 - 【第1个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:18,960 - 【第10个线程】释放连接
    2014-11-19 11:34:18,961 - 【第1个线程】子节点中,我果然是老大/disLocks/sub0000000004
    2014-11-19 11:34:18,964 - 【第1个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:20,964 - 【第1个线程】删除本节点:/disLocks/sub0000000004
    2014-11-19 11:34:20,967 - 【第5个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:20,969 - 【第5个线程】子节点中,我果然是老大/disLocks/sub0000000005
    2014-11-19 11:34:20,971 - 【第1个线程】释放连接
    2014-11-19 11:34:20,971 - 【第5个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:22,971 - 【第5个线程】删除本节点:/disLocks/sub0000000005
    2014-11-19 11:34:22,974 - 【第2个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:22,978 - 【第2个线程】子节点中,我果然是老大/disLocks/sub0000000006
    2014-11-19 11:34:22,979 - 【第5个线程】释放连接
    2014-11-19 11:34:22,981 - 【第2个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:24,981 - 【第2个线程】删除本节点:/disLocks/sub0000000006
    2014-11-19 11:34:24,985 - 【第4个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:24,989 - 【第2个线程】释放连接
    2014-11-19 11:34:24,989 - 【第4个线程】子节点中,我果然是老大/disLocks/sub0000000007
    2014-11-19 11:34:24,995 - 【第4个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:26,995 - 【第4个线程】删除本节点:/disLocks/sub0000000007
    2014-11-19 11:34:26,998 - 【第8个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:27,000 - 【第8个线程】子节点中,我果然是老大/disLocks/sub0000000008
    2014-11-19 11:34:27,004 - 【第8个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:27,004 - 【第4个线程】释放连接
    2014-11-19 11:34:29,004 - 【第8个线程】删除本节点:/disLocks/sub0000000008
    2014-11-19 11:34:29,007 - 【第7个线程】收到情报,排我前面的家伙已挂,我是不是可以出山了?
    2014-11-19 11:34:29,009 - 【第7个线程】子节点中,我果然是老大/disLocks/sub0000000009
    2014-11-19 11:34:29,010 - 【第8个线程】释放连接
    2014-11-19 11:34:29,011 - 【第7个线程】获取锁成功,赶紧干活!
    2014-11-19 11:34:31,011 - 【第7个线程】删除本节点:/disLocks/sub0000000009
    2014-11-19 11:34:31,017 - 【第7个线程】释放连接
    2014-11-19 11:34:31,017 - 所有线程运行结束!
  • 相关阅读:
    tile38 复制配置
    The Guardian’s Migration from MongoDB to PostgreSQL on Amazon RDS
    tile38 一款开源的geo 数据库
    sqler sql 转rest api 的docker 镜像构建(续)使用源码编译
    sqler sql 转rest api javascript 试用
    sqler sql 转rest api redis 接口使用
    sqler sql 转rest api 的docker image
    sqler sql 转rest api 的工具试用
    apache geode 试用
    benthos v1 的一些新功能
  • 原文地址:https://www.cnblogs.com/lqmblog/p/8795596.html
Copyright © 2020-2023  润新知