Zookeeper学习(九):ZooKeeper 实现分布式锁

1.什么是分布式锁


       一般的锁:一般我们说的锁是但进程多线程的锁,在多线程并发编程中,用于线程之间的数据同步,保护共享资源的访问


       分布式锁:分布式锁指的是在分布式环境下,保护跨进程,跨主机,跨网络的共享资源,实现互斥访问,保证一致性。

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁


2.分布式锁的架构图


3.分布式锁的算法流程



 

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.jike.lock;  
  2.   
  3. import java.util.concurrent.TimeUnit;  
  4.   
  5. public interface DistributedLock  
  6.       
  7.       
  8.     public void acquire() throws Exception;  
  9.   
  10.       
  11.     public boolean acquire(long time, TimeUnit unit) throws Exception;  
  12.   
  13.       
  14.     public void release() throws Exception;  
  15.   
  16.   
  17.  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.jike.lock;  
  2.   
  3. import java.util.Collections;  
  4. import java.util.Comparator;  
  5. import java.util.List;  
  6. import java.util.concurrent.CountDownLatch;  
  7. import java.util.concurrent.TimeUnit;  
  8.   
  9. import org.I0Itec.zkclient.IZkDataListener;  
  10. import org.I0Itec.zkclient.ZkClient;  
  11. import org.I0Itec.zkclient.exception.ZkNoNodeException;  
  12.   
  13. public class BaseDistributedLock  
  14.       
  15.     private final ZkClientExt client;  
  16.     private final String  path;  
  17.       
  18.     //zookeeper中locker节点的路径  
  19.     private final String  basePath;  
  20.     private final String  lockName;  
  21.     private static final Integer  MAX_RETRY_COUNT 10 
  22.           
  23.     public BaseDistributedLock(ZkClientExt client, String path, String lockName){  
  24.   
  25.         this.client client;  
  26.         this.basePath path;  
  27.         this.path path.concat("/").concat(lockName);        
  28.         this.lockName lockName;  
  29.           
  30.      
  31.       
  32.     private void deleteOurPath(String ourPath) throws Exception{  
  33.         client.delete(ourPath);  
  34.      
  35.       
  36.     private String createLockNode(ZkClient client,  String path) throws Exception{  
  37.           
  38.         return client.createEphemeralSequential(path, null);  
  39.      
  40.       
  41.     private boolean waitToLock(long startMillis, Long millisToWait, String ourPath) throws Exception{  
  42.           
  43.         boolean  haveTheLock false 
  44.         boolean  doDelete false 
  45.           
  46.         try  
  47.          
  48.    
  49.             while !haveTheLock  
  50.              
  51.                 //获取lock节点下的所有节点  
  52.                 List children getSortedChildren();  
  53.                 String sequenceNodeName ourPath.substring(basePath.length()+1);  
  54.   
  55.                 //获取当前节点的在所有节点列表中的位置  
  56.                 int  ourIndex children.indexOf(sequenceNodeName);  
  57.                 //节点位置小于0,说明没有找到节点  
  58.                 if ourIndex<</span>0 ){  
  59.                     throw new ZkNoNodeException("节点没有找到: " sequenceNodeName);  
  60.                  
  61.                   
  62.                 //节点位置大于0说明还有其他节点在当前的节点前面,就需要等待其他的节点都释放  
  63.                 boolean isGetTheLock ourIndex == 0 
  64.                 String  pathToWatch isGetTheLock null children.get(ourIndex 1);  
  65.   
  66.                 if isGetTheLock ){  
  67.                       
  68.                     haveTheLock true 
  69.                       
  70.                 }else 
  71.                       
  72.                     String  previousSequencePath basePath .concat( "/" .concat( pathToWatch );  
  73.                     final CountDownLatch    latch new CountDownLatch(1);  
  74.                     final IZkDataListener previousListener new IZkDataListener()  
  75.                           
  76.                         public void handleDataDeleted(String dataPath) throws Exception  
  77.                             latch.countDown();            
  78.                          
  79.                           
  80.                         public void handleDataChange(String dataPath, Object data) throws Exception  
  81.                             // ignore                                     
  82.                          
  83.                     };  
  84.   
  85.                     try   
  86.                                        
  87.                         //如果节点不存在会出现异常  
  88.                         client.subscribeDataChanges(previousSequencePath, previousListener);  
  89.                           
  90.                         if millisToWait != null  
  91.                          
  92.                             millisToWait -= (System.currentTimeMillis() startMillis);  
  93.                             startMillis System.currentTimeMillis();  
  94.                             if millisToWait <= 0  
  95.                              
  96.                                 doDelete true   // timed out delete our node  
  97.                                 break 
  98.                              
  99.   
  100.                             latch.await(millisToWait, TimeUnit.MICROSECONDS);  
  101.                          
  102.                         else  
  103.                          
  104.                             latch.await();  
  105.                          
  106.                      
  107.                     catch ZkNoNodeException   
  108.                      
  109.                         //ignore  
  110.                     }finally 
  111.                         client.unsubscribeDataChanges(previousSequencePath, previousListener);  
  112.                      
  113.   
  114.                  
  115.              
  116.          
  117.         catch Exception  
  118.          
  119.             //发生异常需要删除节点  
  120.             doDelete true 
  121.             throw e;  
  122.          
  123.         finally  
  124.          
  125.             //如果需要删除节点  
  126.             if doDelete  
  127.              
  128.                 deleteOurPath(ourPath);  
  129.              
  130.          
  131.         return haveTheLock;  
  132.      
  133.       
  134.     private String getLockNodeNumber(String str, String lockName)  
  135.      
  136.         int index str.lastIndexOf(lockName);  
  137.         if index >= 0  
  138.          
  139.             index += lockName.length();  
  140.             return index <= str.length() str.substring(index) "" 
  141.          
  142.         return str;  
  143.      
  144.       
  145.     List getSortedChildren() throws Exception  
  146.      
  147.         try 
  148.               
  149.             List children client.getChildren(basePath);  
  150.             Collections.sort  
  151.              
  152.                 children,  
  153.                 new Comparator()  
  154.                  
  155.                     public int compare(String lhs, String rhs)  
  156.                      
  157.                         return getLockNodeNumber(lhs, lockName).compareTo(getLockNodeNumber(rhs, lockName));  
  158.                      
  159.                  
  160.             );  
  161.             return children;  
  162.               
  163.         }catch(ZkNoNodeException e){  
  164.               
  165.             client.createPersistent(basePath, true);  
  166.             return getSortedChildren();  
  167.               
  168.          
  169.      
  170.       
  171.     protected void releaseLock(String lockPath) throws Exception{  
  172.         deleteOurPath(lockPath);      
  173.           
  174.      
  175.       
  176.       
  177.     protected String attemptLock(long time, TimeUnit unit) throws Exception{  
  178.           
  179.         final long      startMillis System.currentTimeMillis();  
  180.         final Long      millisToWait (unit != nullunit.toMillis(time) null 
  181.   
  182.         String          ourPath null 
  183.         boolean         hasTheLock false 
  184.         boolean         isDone false 
  185.         int             retryCount 0 
  186.           
  187.         //网络闪断需要重试一试  
  188.         while !isDone  
  189.          
  190.             isDone true 
  191.   
  192.             try  
  193.              
  194.                 ourPath createLockNode(client, path);  
  195.                 hasTheLock waitToLock(startMillis, millisToWait, ourPath);  
  196.              
  197.             catch ZkNoNodeException  
  198.              
  199.                 if retryCount++ MAX_RETRY_COUNT  
  200.                  
  201.                     isDone false 
  202.                  
  203.                 else  
  204.                  
  205.                     throw e;  
  206.                  
  207.              
  208.          
  209.         if hasTheLock  
  210.          
  211.             return ourPath;  
  212.          
  213.   
  214.         return null 
  215.      
  216.       
  217.       
  218.  

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. package com.jike.lock;  
  2.   
  3. import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer;  
  4.   
  5. public class TestDistributedLock  
  6.       
  7.     public static void main(String[] args)  
  8.           
  9.         final ZkClientExt zkClientExt1 new ZkClientExt("192.168.1.105:2181"50005000new BytesPushThroughSerializer());  
  10.         final SimpleDistributedLockMutex mutex1 new SimpleDistributedLockMutex(zkClientExt1, "/Mutex");  
  11.           
  12.         final ZkClientExt zkClientExt2 new ZkClientExt("192.168.1.105:2181"50005000new BytesPushThroughSerializer());  
  13.         final SimpleDistributedLockMutex mutex2 new SimpleDistributedLockMutex(zkClientExt2, "/Mutex");  
  14.           
  15.         try  
  16.             mutex1.acquire();  
  17.             System.out.println("Client1 locked");  
  18.             Thread client2Thd new Thread(new Runnable()  
  19.                   
  20.                 public void run()  
  21.                     try  
  22.                         mutex2.acquire();  
  23.                         System.out.println("Client2 locked");  
  24.                         mutex2.release();  
  25.                         System.out.println("Client2 released lock");  
  26.                           
  27.                     catch (Exception e)  
  28.                         e.printStackTrace();  
  29.                                     
  30.                  
  31.             });  
  32.             client2Thd.start();  
  33.             Thread.sleep(5000);  
  34.             mutex1.release();             
  35.             System.out.println("Client1 released lock");  
  36.               
  37.             client2Thd.join();  
  38.               
  39.         catch (Exception e)  
  40.   
  41.             e.printStackTrace();  
  42.          
  43.           
  44.      
  45.   
  46.  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值