zookeeper应用场景练习(分布式锁)
在寻常的高并发的程序中。为了保证数据的一致性。因此都会用到锁。来对当前的线程进行锁定。在单机操作中。非常好做到,比方能够採用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应用场景练习(分布式锁)的更多相关文章
- zookeeper适用场景:分布式锁实现
问题导读:1.zookeeper如何实现分布式锁?2.什么是羊群效应?3.zookeeper如何释放锁? 在zookeeper应用场景有关于分布式集群配置文件同步问题的描述,设想一下如果有100台机器 ...
- Zookeeper是如何实现分布式锁的
[toc] Zookeeper是如何实现分布式锁的 标签 : Zookeeper 分布式 实现分布式锁要考虑的重要问题 1. 三个核心要素 加锁, 解锁, 锁超时 2. 三个问题 要保证原子性操作, ...
- ZooKeeper典型应用场景:分布式锁
分布式锁是控制分布式系统之间同步访问共享资源的一种方式.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致 ...
- Zookeeper绍二(分布式锁介)
一.为什么会有分布式锁? 在多线程环境下,由于上下文的切换,数据可能出现不一致的情况或者数据被污染,我们需要保证数据安全,所以想到了加锁. 所谓的加锁机制呢,就是当一个线程访问该类的某个数据时,进行保 ...
- 服务注册中心之ZooKeeper系列(三) 实现分布式锁
通过ZooKeeper的有序节点.节点路径不回重复.还有节点删除会触发Wathcer事件的这些特性,我们可以实现分布式锁. 一.思路 zookeeper中创建一个根节点Locks,用于后续各个客户端的 ...
- zookeeper【5】分布式锁
我们常说的锁是单进程多线程锁,在多线程并发编程中,用于线程之间的数据同步,保护共享资源的访问.而分布式锁,指在分布式环境下,保护跨进程.跨主机.跨网络的共享资源,实现互斥访问,保证一致性. 架构图: ...
- 基于zookeeper或redis实现分布式锁
前言 在分布式系统中,分布式锁是为了解决多实例之间的同步问题.例如master选举,能够获取分布式锁的就是master,获取失败的就是slave.又或者能够获取锁的实例能够完成特定的操作. 目前比较常 ...
- 基于ZooKeeper的三种分布式锁实现
[欢迎关注公众号:程序猿讲故事 (codestory),及时接收最新文章] 今天介绍基于ZooKeeper的分布式锁的简单实现,包括阻塞锁和非阻塞锁.同时增加了网上很少介绍的基于节点的非阻塞锁实现,主 ...
- 跟着实例学习ZooKeeper的用法: 分布式锁
锁 分布式的锁全局同步, 这意味着任何一个时间点不会有两个客户端都拥有相同的锁. 可重入锁Shared Reentrant Lock 首先我们先看一个全局可重入的锁. Shared意味着锁是全局可见的 ...
- Zookeeper系列3 实现分布式锁
基本思路 1 client调用create()方法创建“/locks/_lock_”临时顺序节点,注意节点类型是EPHEMERAL_SEQUENTIAL 2 client调用getChildren(& ...
随机推荐
- struts2解决动态多文件上传的问题(上传文件与数据库字段一一对应)(转)
struts2多文件上传我想只要会用struts2的朋友都不会陌生,但是怎么在action中根据用户上传的文 件把文件路径写到数据库中对应的字段上呢?ps:我的意思是这样,页面上有固定的5个上传文件的 ...
- 基于bootstrap的分页组件-Bootstrap Paginator
效果
- 小记如何有顺序的搭建一个Spring的web项目
如何有顺序的搭建一个Spring的web项目 一.新建一个简单的maven,war工程 eclipse下如有报错,右键 Deployment 单击 Generate 生成web.xml后可解决报错 二 ...
- Mysql学习总结(32)——MySQL分页技术详解
1.什么是数据分页:数据分页就是将很多条记录像书本一样分页,每页显示多少行记录: 2.为什么要数据分页:当我们进行sql语句查询时,假如数据有成千上万行记录,如果在同一个页面去显示,那这个页面得有多大 ...
- 监控iis计数器
- 洛谷 P1461 海明码 Hamming Codes
P1461 海明码 Hamming Codes 题目描述 给出 N,B 和 D,要求找出 N 个由0或1组成的编码(1 <= N <= 64),每个编码有 B 位(1 <= B &l ...
- Qt程序打包成exe可执行文件
很多Qt爱好者想发布自己的Qt软件,但却发现在其他没有安装Qt SDK的机器上无法运行,这就是本文想要说明的问题.现在网上大部分软件都要发布自己开发的应用程序,都会打包到exe文件中,待安装完exe文 ...
- C++编写绚丽的界面
近期项目特别的操蛋,要用C++写出各种变态界面,今晚上赶工总算有了一点小的收货. 因为没有时间去写博文 ,等项目期完了 准备 写一系列 怎样在C++/win32/mfc开发高质量 可扩展界面组建 ...
- vuex3
以下是一个表示“单向数据流”理念的极简示意: 但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏: 多个视图依赖于同一状态. 来自不同视图的行为需要变更同一状态. 这就是 Vue ...
- Document properties
http://devnet.kentico.com/docs/7_0/devguide/index.html?document_properties_overview.htm You can edit ...