在寻常的高并发的程序中。为了保证数据的一致性。因此都会用到锁。来对当前的线程进行锁定。在单机操作中。非常好做到,比方能够採用Synchronized、Lock或者其它的读写多来锁定当前的线程。可是在分布式的系统中,就非常难做到这一点。因此能够採用zookeeper中节点的特性来满足这一点。

大致实现的思路例如以下。

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

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

3.假设是的话,就获得了运行当前任务的锁

4.假设不是的话。就找到比自己小的节点,然后进行监听,假设被删除的话。就能够获得锁

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

package com.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch; import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorWatcher;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class DistributedLock { private String lockName;
private final int timeOut = 3000;
private final String root = "/locks";
private String myZnode;// 代表当前节点信息
private String waitZnode;
private static Logger logger = LoggerFactory
.getLogger(DistributedLock.class);
private CuratorFramework client;
private CountDownLatch latch = new CountDownLatch(1); public DistributedLock(String connectString, String lockName) {
this.lockName = lockName;
client = CuratorFrameworkFactory.builder().connectionTimeoutMs(timeOut)
.connectString(connectString)
.retryPolicy(new RetryNTimes(3, 3000)).build();
ConnectionStateListener listener = new ConnectionStateListener() { public void stateChanged(CuratorFramework client,
ConnectionState newState) {
if (newState == ConnectionState.CONNECTED) {
logger.info("连接成功了");
latch.countDown();
}
}
}; client.getConnectionStateListenable().addListener(listener);
client.start();
try {
latch.await();
createRoot();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* @Title: 创建根节点root
* @Description: TODO
* @param
* @return void
* @throws
*/
private void createRoot() {
try {
Stat stat = client.checkExists().forPath(root);
if (stat != null) {
logger.info("root has already exists");
} else {
// 创建跟节点
client.create().creatingParentsIfNeeded().forPath(root); }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} public void getLocks() { try {
myZnode = client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath(root + "/" + lockName);
logger.info(myZnode + "has created");
// 取出全部的子节点。然后找出比自己小的节点。进行监听的设置
List<String> subNodes = client.getChildren().forPath(root);
// 取出全部带有lockname的节点信息
List<String> lockObjNodes = new ArrayList<String>();
for (String node : subNodes) {
if (node.contains(lockName)) {
lockObjNodes.add(node);
}
}
// 对当前节点进行排序
Collections.sort(lockObjNodes);
// 推断当前的节点是不是最小的节点
if (myZnode.equals(root + "/" + lockObjNodes.get(0))) {
doAction();
} else {
// 找到比自己节点大一的节点进行监听
String subMyZone = myZnode
.substring(myZnode.lastIndexOf("/") + 1);
waitZnode = lockObjNodes.get(Collections.binarySearch(
lockObjNodes, subMyZone) - 1);
// 对节点进行监听
Stat stat = client.checkExists()
.usingWatcher(deleteNodeWatcher).forPath("/"+waitZnode);
if (stat != null) {
System.out.println(Thread.currentThread().getName()
+ "处于等待状态");
} else {
doAction();
}
}
} catch (Exception e) {
logger.error(e.getMessage());
}
} // 删除节点的事件监听
CuratorWatcher deleteNodeWatcher = new CuratorWatcher() { public void process(WatchedEvent event) throws Exception { if (event.getType() == EventType.NodeDeleted) {
doAction();
}
}
}; private void doAction() {
System.out.println(Thread.currentThread().getName() + "開始运行");
client.close();
}
}

以下来測试一下

/**
* @FileName: TestCurrentZk.java
* @Package:com.test
* @Description: TODO
* @author: LUCKY
* @date:2016年2月2日 下午11:36:04
* @version V1.0
*/
package com.test; /**
* @ClassName: TestCurrentZk
* @Description: TODO
* @author: LUCKY
* @date:2016年2月2日 下午11:36:04
*/
public class TestCurrentZk { public static void main(String[] args) throws Exception {
Thread threads[] = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
ClientTest clientTest = new ClientTest(
"100.66.162.36:2181", "locknametest");
clientTest.getLocks();
}
}); threads[i].start(); }
Thread.sleep(Integer.MAX_VALUE);
}
}

zookeeper应用场景练习(分布式锁)的更多相关文章

  1. zookeeper适用场景:分布式锁实现

    问题导读:1.zookeeper如何实现分布式锁?2.什么是羊群效应?3.zookeeper如何释放锁? 在zookeeper应用场景有关于分布式集群配置文件同步问题的描述,设想一下如果有100台机器 ...

  2. Zookeeper是如何实现分布式锁的

    [toc] Zookeeper是如何实现分布式锁的 标签 : Zookeeper 分布式 实现分布式锁要考虑的重要问题 1. 三个核心要素 加锁, 解锁, 锁超时 2. 三个问题 要保证原子性操作, ...

  3. ZooKeeper典型应用场景:分布式锁

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致 ...

  4. Zookeeper绍二(分布式锁介)

    一.为什么会有分布式锁? 在多线程环境下,由于上下文的切换,数据可能出现不一致的情况或者数据被污染,我们需要保证数据安全,所以想到了加锁. 所谓的加锁机制呢,就是当一个线程访问该类的某个数据时,进行保 ...

  5. 服务注册中心之ZooKeeper系列(三) 实现分布式锁

    通过ZooKeeper的有序节点.节点路径不回重复.还有节点删除会触发Wathcer事件的这些特性,我们可以实现分布式锁. 一.思路 zookeeper中创建一个根节点Locks,用于后续各个客户端的 ...

  6. zookeeper【5】分布式锁

    我们常说的锁是单进程多线程锁,在多线程并发编程中,用于线程之间的数据同步,保护共享资源的访问.而分布式锁,指在分布式环境下,保护跨进程.跨主机.跨网络的共享资源,实现互斥访问,保证一致性. 架构图: ...

  7. 基于zookeeper或redis实现分布式锁

    前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...

  8. 基于ZooKeeper的三种分布式锁实现

    [欢迎关注公众号:程序猿讲故事 (codestory),及时接收最新文章] 今天介绍基于ZooKeeper的分布式锁的简单实现,包括阻塞锁和非阻塞锁.同时增加了网上很少介绍的基于节点的非阻塞锁实现,主 ...

  9. 跟着实例学习ZooKeeper的用法: 分布式锁

    锁 分布式的锁全局同步, 这意味着任何一个时间点不会有两个客户端都拥有相同的锁. 可重入锁Shared Reentrant Lock 首先我们先看一个全局可重入的锁. Shared意味着锁是全局可见的 ...

  10. Zookeeper系列3 实现分布式锁

    基本思路 1 client调用create()方法创建“/locks/_lock_”临时顺序节点,注意节点类型是EPHEMERAL_SEQUENTIAL 2 client调用getChildren(& ...

随机推荐

  1. [luogu] P2569 [SCOI2010]股票交易 (单调队列优化)

    P2569 [SCOI2010]股票交易 题目描述 最近 \(\text{lxhgww}\) 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,\(\te ...

  2. W10子系统UBantu命令安装Redis及其启动

    W10子系统UBantu命令安装Redis及其启动 打开W10子系统UBantu 安装Redis $sudo apt-get install redis-server 启动Redis redis-se ...

  3. jQuery判断浏览器类型和版本

    jquery 判断浏览器类型 例:   if($.browser.msie) { alert("这是一个IE浏览器"); }else if($.browser.opera) { a ...

  4. ZOJ 2836

    求不比M大的可以被集合任一个数整除的数的个数.(容斥原理) #include <iostream> #include <cstdio> #include <algorit ...

  5. BCB使用线程删除目录中的图片

    BCB新建线程DeleteImgThread类.其会默认继承Thread类,然后在Execute函数中编写代码, void __fastcall DeleteImgThread::Execute() ...

  6. iOS UI10_带分区的省市区

    // // MainViewController.m // UI10_带分区的省市区 // // Created by dllo on 15/8/11. // Copyright (c) 2015年 ...

  7. android sudio 执行的中文是乱码解决方式

    1.File-->Setings-->查找file encodings 例如以下图 2.将 IDE Encoding .Project Encoding.Default encoding ...

  8. DB-MySQL:目录

    ylbtech-DB-MySQL:目录 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   作者:ylbtech出处:http://ylbt ...

  9. Shiro授权认证原理和流程

    先来张图: 这是一张shiro的功能图: Authentication: 身份认证/登录,验证用户是否拥有相应的身份 Authorization: 授权/权限验证,验证某个已认证的用户是否拥有某个权限 ...

  10. java中三个类别加载器的关系以及各自加载的类的范围

    Java在需要使用类别的时候,才会将类别加载,Java的类别载入是由类别载入器(Class loader)来达到的,预设上,在程序启动之后,主要会有三个类别加载器:Bootstrap Loader.E ...