在寻常的高并发的程序中。为了保证数据的一致性。因此都会用到锁。来对当前的线程进行锁定。在单机操作中。非常好做到,比方能够採用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. IIC 原理讲解

    IIC具体是什么这里我就不细说了,只收集一些关于IIC的原理. IIC总线优点是节约总线数,稳定,快速, 是目前芯片制造上非常 流行的一种总线,大多数单片机已经片内集成了IIC总线接口,无 需用户自己 ...

  2. 题解 P3978 【[TJOI2015]概率论】

    这道题...好像是第一道我自己切出来的黑题... 先说一句,牛顿二项式蒟蒻并不会,可以说是直接套结论. 求诸位老爷轻喷. 这道题用卡特兰数搞. 卡特兰数这玩意从普及组初赛一路考到省选,十分有用. 如果 ...

  3. Jenkins学习总结(4)——持续集成,持续交付,持续部署之间的区别

    经常会听到持续集成,持续交付,持续部署,三者究竟是什么,有何联系和区别呢? 假如把开发工作流程分为以下几个阶段: 编码 -> 构建 -> 集成 -> 测试 -> 交付 -> ...

  4. 洛谷 P1518 两只塔姆沃斯牛 The Tamworth Two

    P1518 两只塔姆沃斯牛 The Tamworth Two 题目背景 题目描述 两只牛逃跑到了森林里.农夫John开始用他的专家技术追捕这两头牛.你的任务是模拟他们的行为(牛和John). 追击在1 ...

  5. oracle学习之第一个存储过程:打印Hello World

    数据库对象:表.视图.索引.序列.同义词.存储过程.存储函数 存储过程:指的是存储在数据库中供全部用户程序调用的子程序叫存储过程.存储函数 存储过程和存储函数的同样点:完毕特定功能的程序 存储过程和存 ...

  6. POJ 1942

    开始时竟然用了分情况讨论. 仔细思考一下,哈哈,发现不过是多重集合的组合数而已. #include <iostream> #include <cstdio> #include ...

  7. IntelliJ IDEA could not autowire no beans of 'Decoder'

    IntelliJ IDEA could not autowire no beans of  'Decoder' 学习了:http://blog.csdn.net/u012453843/article/ ...

  8. start_kernel——boot_cpu_init及PER_CPU

    init/main.c /* * Activate the first processor. */ static void __init boot_cpu_init(void) { int cpu = ...

  9. MapReduce(十六): 写数据到HDFS的源代码分析

    1)   LineRecordWriter负责把Key,Value的形式把数据写入到DFSOutputStream watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZ ...

  10. UI组件之TextView及其子类(一)TextView和EditText

    先来整理一下TexView,EditView的使用方法. Textview是最主要的组件.直接继承了View,也是众多组件的父类.所以了解她的属性会对学习其它组件非常有帮助. TextView的属性: ...