分布式锁系列文章

分布式锁(1) ----- 介绍和基于数据库的分布式锁

分布式锁(2) ----- 基于redis的分布式锁

分布式锁(3) ----- 基于zookeeper的分布式锁

代码:https://github.com/shuo123/distributeLock

思路

利用zookeeper的临时有序节点和watch实现,思路如下:

  1. 获取锁的请求在锁的根目录下调用create()创建临时有序节点
  2. 在锁的根目录下调用getChildren()获取所有子节点
  3. 判断步骤1创建的临时有序节点是否是所有子节点中最小的一个,是则获取锁,结束获取
  4. 否则对排在该节点的前一个节点调用exists()判断节点是否存在,并设置watch监听节点的删除事件
  5. 如果步骤4返回节点不存在转到步骤2,否则等待节点删除再转到步骤2

注意:

  1. 创建临时节点,是在请求锁的客户端挂了,节点会自动删除
  2. 创建有序节点,是为了防止群体效应,只需监听前一个节点的删除事件,不用监听所有节点的删除事件
  3. 该思路实现的是公平锁

实现

java实现

public boolean tryLock(long waitTime){
try {
//1.创建临时有序节点
myZNode = zk.create(root + "/" + lockName + "-", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
return waitForLock(waitTime);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
} private boolean waitForLock(long watiTime) {
long start = System.currentTimeMillis();
try {
while (System.currentTimeMillis() - start < watiTime) {
//2.获取子节点
List<String> children = zk.getChildren(root, false);
List<String> lockNodes = new ArrayList<>();
for (String s : children) {
if (s.startsWith(lockName)) {
lockNodes.add(s);
}
}
Collections.sort(lockNodes);
//3.判断是否最小节点
if (myZNode.equals(root + "/" + lockNodes.get(0))) {
return true;
}
//4.监听前一个节点删除事件
String seq = myZNode.substring(myZNode.lastIndexOf('/') + 1);
String waitNode = lockNodes.get(Collections.binarySearch(lockNodes, seq) - 1);
CountDownLatch latch = new CountDownLatch(1);
Stat stat = zk.exists(root + "/" + waitNode, watchedEvent -> {
if (watchedEvent.getType() == Watcher.Event.EventType.NodeDeleted) {
latch.countDown();
}
});
if (stat != null) {
latch.await(watiTime - System.currentTimeMillis() + start, TimeUnit.MILLISECONDS);
}
}
}catch (Exception e){
deleteNode();
e.printStackTrace();
}
deleteNode();
return false;
} public boolean unlock() {
return deleteNode();
} private boolean deleteNode(){
try {
zk.delete(myZNode, -1);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
return false;
}

测试代码

private static class ZoookeeperLockTest implements Runnable {

    private CyclicBarrier barrier;

    ZoookeeperLockTest(CyclicBarrier barrier) {
this.barrier = barrier;
} @Override
public void run() {
try {
CountDownLatch latch = new CountDownLatch(1);
ZooKeeper zk = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183", 5000, WatchedEvent -> {
latch.countDown();
});
latch.await();
try {
DistributeLock lock = new ZookeeperLock(zk, "lock");
barrier.await();
lock.tryLock(Integer.MAX_VALUE);
try {
System.out.println(Thread.currentThread().getName() + "get lock");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "get unlock");
} finally {
lock.unlock();
}
} finally {
zk.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

缺点与解决方案

没有实现重入。可以使用threadlocal保存重入次数,每次解锁-1,到0时才删除节点

curator

curator是apache的顶级开源项目,实现了分布式锁及队列、选举等多种高级功能。同时优化了zookeeper原生api的很多问题,如支持自动连接,递归创建删除节点等等。

private static class CuratorLockTest implements Runnable {

    private CyclicBarrier barrier;

    CuratorLockTest(CyclicBarrier barrier) {
this.barrier = barrier;
} @Override
public void run() {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183")
.sessionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
client.start();
InterProcessLock lock = new InterProcessMutex(client, "/locks/curator-lock");
try{
lock.acquire();
try {
System.out.println(Thread.currentThread().getName() + "get lock");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + "get unlock");
}finally {
lock.release();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
client.close();
}
}
}

参考资料

http://zookeeper.apache.org/doc/r3.4.13/recipes.html#sc_recipes_Locks

https://www.cnblogs.com/seesun2012/p/9214653.html

分布式锁(3) ----- 基于zookeeper的分布式锁的更多相关文章

  1. 基于Zookeeper的分布式锁(干干干货)

    原文地址: https://juejin.im/post/5df883d96fb9a0163514d97f 介绍 为什么使用锁 锁的出现是为了解决资源争用问题,在单进程环境下的资源争夺可以使用 JDK ...

  2. 基于 Zookeeper 的分布式锁实现

    1. 背景 最近在学习 Zookeeper,在刚开始接触 Zookeeper 的时候,完全不知道 Zookeeper 有什么用.且很多资料都是将 Zookeeper 描述成一个“类 Unix/Linu ...

  3. 【连载】redis库存操作,分布式锁的四种实现方式[一]--基于zookeeper实现分布式锁

    一.背景 在电商系统中,库存的概念一定是有的,例如配一些商品的库存,做商品秒杀活动等,而由于库存操作频繁且要求原子性操作,所以绝大多数电商系统都用Redis来实现库存的加减,最近公司项目做架构升级,以 ...

  4. 基于ZooKeeper的分布式Session实现(转)

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  5. 基于ZooKeeper的分布式Session实现

    1.   认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...

  6. Java Web学习总结(20)——基于ZooKeeper的分布式session实现

    1.   认识ZooKeeper ZooKeeper-- "动物园管理员".动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始 ...

  7. ShardingJdbc基于Zookeeper实现分布式治理

    随着数据规模的不断膨胀,使用多节点集群的分布式方式逐渐成为趋势.在这种情况下,如何高效.自动化管理集群节点,实现不同节点的协同工作,配置一致性,状态一致性,高可用性,可观测性等,就成为一个重要的挑战. ...

  8. 基于zookeeper实现分布式配置中心(二)

    上一篇(基于zookeeper实现分布式配置中心(一))讲述了zookeeper相关概念和工作原理.接下来根据zookeeper的特性,简单实现一个分布式配置中心. 配置中心的优势 1.各环境配置集中 ...

  9. 基于ZooKeeper的分布式锁和队列

    在分布式系统中,往往需要一些分布式同步原语来做一些协同工作,上一篇文章介绍了Zookeeper的基本原理,本文介绍下基于Zookeeper的Lock和Queue的实现,主要代码都来自Zookeeper ...

随机推荐

  1. element ui 版本升级

    element ui 版本升级 1. 卸载之前版本 npm uninstall element-ui 2.重新安装element-ui npm i element-ui 3.就如package.jso ...

  2. Docker部署Python项目

    简介 软件开发最大的麻烦事之一就是环境配置,操作系统设置,各种库和组件的安装.只有它们都正确,软件才能运行.如果从一种操作系统里面运行另一种操作系统,通常我们采取的策略就是引入虚拟机,比如在 Wind ...

  3. Spring — 循环依赖

    读完这篇文章你将会收获到 Spring 循环依赖可以分为哪两种 Spring 如何解决 setter 循环依赖 Spring 为何是三级缓存 , 二级不行 ? Spring 为啥不能解决构造器循环依赖 ...

  4. windows7 添加tomcat(解压缩版或者免安装版)自启动服务

    https://blog.csdn.net/piggachen/article/details/69943223 :(service.bat方式安装服务或者windows任务方式添加) https:/ ...

  5. Java 内存回收机制

    当执行构造方法生成一个对象时,需要占用各种系统资源.当生成的对象不再使用时,就需要返回给操作系统,以免资源的泄露.在各种系统资源中,最常使用的就是内存.Java运行时系统通过垃圾收集周期性地释放无用对 ...

  6. Netty 源码解析(九): connect 过程和 bind 过程分析

    原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第九篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...

  7. Netty系列之源码解析(一)

    本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 当前:Netty 源码解析(一)开始 Netty 源码解析(二): Netty 的 Channel ...

  8. BZOJ 1294 围豆豆 题解

    题目 是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧. 游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗豆子,每颗豆有不同的分值Vi.游 ...

  9. Least Cost Bracket Sequence,题解

    题目链接 题意: 给你一个含有(,),?的序列,每个?变成(或)有一定的花费,问变成课匹配的括号的最小花费. 分析: 首先如果能变成匹配的,那么就有右括号的个数始终不多于左括号且左右括号数量相等,那就 ...

  10. Java基础笔记01-02-03-04

    一.今日内容介绍 1.Java开发环境搭建 2.HelloWorld案例 3.注释.关键字.标识符 4.数据(数据类型.常量) 01java语言概述 * A: java语言概述 * a: Java是s ...