zookeeper分布锁

在平常的高并发的程序中,为了保证数据的一致性,因此都会用到锁,来对当前的线程进行锁定。在单机操作中,很好做到,比如可以采用Synchronized、Lock或者其他的读写多来锁定当前的线程。但是在分布式的系统中,就很难做到这一点。因此可以采用zookeeper中节点的特性来满足这一点。大致实现的思路如下。

 1.每个客户端都去zookeeper上创建临时的顺序节点

 2.客户端判断当前自己创建的节点是不是最小的

 3.如果是的话,就获得了执行当前任务的锁

 4.如果不是的话,就找到比自己小的节点,然后进行监听,如果被删除的话,就可以获得锁


 上面就是大致的实现思路,下面我们来通过代码来实现一下。

 

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">package com.test;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collections;  
  5. import java.util.List;  
  6. import java.util.concurrent.CountDownLatch;  
  7.   
  8. import org.apache.curator.framework.CuratorFramework;  
  9. import org.apache.curator.framework.CuratorFrameworkFactory;  
  10. import org.apache.curator.framework.api.CuratorWatcher;  
  11. import org.apache.curator.framework.state.ConnectionState;  
  12. import org.apache.curator.framework.state.ConnectionStateListener;  
  13. import org.apache.curator.retry.RetryNTimes;  
  14. import org.apache.zookeeper.CreateMode;  
  15. import org.apache.zookeeper.WatchedEvent;  
  16. import org.apache.zookeeper.Watcher.Event.EventType;  
  17. import org.apache.zookeeper.data.Stat;  
  18. import org.slf4j.Logger;  
  19. import org.slf4j.LoggerFactory;  
  20.   
  21. public class DistributedLock {  
  22.   
  23.     private String lockName;  
  24.     private final int timeOut = 3000;  
  25.     private final String root = "/locks";  
  26.     private String myZnode;// 代表当前节点信息  
  27.     private String waitZnode;  
  28.     private static Logger logger = LoggerFactory  
  29.             .getLogger(DistributedLock.class);  
  30.     private CuratorFramework client;  
  31.     private CountDownLatch latch = new CountDownLatch(1);  
  32.   
  33.     public DistributedLock(String connectString, String lockName) {  
  34.         this.lockName = lockName;  
  35.         client = CuratorFrameworkFactory.builder().connectionTimeoutMs(timeOut)  
  36.                 .connectString(connectString)  
  37.                 .retryPolicy(new RetryNTimes(33000)).build();  
  38.         ConnectionStateListener listener = new ConnectionStateListener() {  
  39.   
  40.             public void stateChanged(CuratorFramework client,  
  41.                     ConnectionState newState) {  
  42.                 if (newState == ConnectionState.CONNECTED) {  
  43.                     logger.info("连接成功了");  
  44.                     latch.countDown();  
  45.                 }  
  46.             }  
  47.         };  
  48.   
  49.         client.getConnectionStateListenable().addListener(listener);  
  50.         client.start();  
  51.         try {  
  52.             latch.await();  
  53.             createRoot();  
  54.         } catch (InterruptedException e) {  
  55.             // TODO Auto-generated catch block  
  56.             e.printStackTrace();  
  57.         }  
  58.   
  59.     }  
  60.   
  61.     /** 
  62.      * @Title: 创建根节点root 
  63.      * @Description: TODO 
  64.      * @param 
  65.      * @return void 
  66.      * @throws 
  67.      */  
  68.     private void createRoot() {  
  69.         try {  
  70.             Stat stat = client.checkExists().forPath(root);  
  71.             if (stat != null) {  
  72.                 logger.info("root has already exists");  
  73.             } else {  
  74.                 // 创建跟节点  
  75.                 client.create().creatingParentsIfNeeded().forPath(root);  
  76.   
  77.             }  
  78.         } catch (Exception e) {  
  79.             // TODO Auto-generated catch block  
  80.             e.printStackTrace();  
  81.         }  
  82.     }  
  83.   
  84.     public void getLocks() {  
  85.   
  86.         try {  
  87.             myZnode = client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)  
  88.                     .forPath(root + "/" + lockName);  
  89.             logger.info(myZnode + "has created");  
  90.             // 取出所有的子节点,然后找出比自己小的节点,进行监听的设置  
  91.             List<String> subNodes = client.getChildren().forPath(root);  
  92.             // 取出所有带有lockname的节点信息  
  93.             List<String> lockObjNodes = new ArrayList<String>();  
  94.             for (String node : subNodes) {  
  95.                 if (node.contains(lockName)) {  
  96.                     lockObjNodes.add(node);  
  97.                 }  
  98.             }  
  99.             // 对当前节点进行排序  
  100.             Collections.sort(lockObjNodes);  
  101.             // 判断当前的节点是不是最小的节点  
  102.             if (myZnode.equals(root + "/" + lockObjNodes.get(0))) {  
  103.                 doAction();  
  104.             } else {  
  105.                 // 找到比自己节点大一的节点进行监听  
  106.                 String subMyZone = myZnode  
  107.                         .substring(myZnode.lastIndexOf("/") + 1);  
  108.                 waitZnode = lockObjNodes.get(Collections.binarySearch(  
  109.                         lockObjNodes, subMyZone) - 1);  
  110.                 // 对节点进行监听  
  111.                 Stat stat = client.checkExists()  
  112.                         .usingWatcher(deleteNodeWatcher).forPath("/"+waitZnode);  
  113.                 if (stat != null) {  
  114.                     System.out.println(Thread.currentThread().getName()  
  115.                             + "处于等待状态");  
  116.                 } else {  
  117.                     doAction();  
  118.                 }  
  119.             }  
  120.         } catch (Exception e) {  
  121.             logger.error(e.getMessage());  
  122.         }  
  123.     }  
  124.   
  125.     // 删除节点的事件监听  
  126.     CuratorWatcher deleteNodeWatcher = new CuratorWatcher() {  
  127.   
  128.         public void process(WatchedEvent event) throws Exception {  
  129.   
  130.             if (event.getType() == EventType.NodeDeleted) {  
  131.                 doAction();  
  132.             }  
  133.         }  
  134.     };  
  135.   
  136.     private void doAction() {  
  137.         System.out.println(Thread.currentThread().getName() + "开始执行");  
  138.         client.close();  
  139.     }  
  140. }  
  141. </span>  


 下面来测试一下

 

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family:Comic Sans MS;font-size:18px;">/**      
  2.  * @FileName: TestCurrentZk.java    
  3.  * @Package:com.test    
  4.  * @Description: TODO   
  5.  * @author: LUCKY     
  6.  * @date:2016年2月2日 下午11:36:04    
  7.  * @version V1.0      
  8.  */  
  9. package com.test;  
  10.   
  11. /** 
  12.  * @ClassName: TestCurrentZk 
  13.  * @Description: TODO 
  14.  * @author: LUCKY 
  15.  * @date:2016年2月2日 下午11:36:04 
  16.  */  
  17. public class TestCurrentZk {  
  18.   
  19.     public static void main(String[] args) throws Exception {  
  20.         Thread threads[] = new Thread[10];  
  21.         for (int i = 0; i < threads.length; i++) {  
  22.             threads[i] = new Thread(new Runnable() {  
  23.                 public void run() {  
  24.                     ClientTest clientTest = new ClientTest(  
  25.                             "100.66.162.36:2181""locknametest");  
  26.                     clientTest.getLocks();  
  27.                 }  
  28.             });  
  29.   
  30.             threads[i].start();  
  31.   
  32.         }  
  33.         Thread.sleep(Integer.MAX_VALUE);  
  34.     }  
  35. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值