基于zk“临时顺序节点“的分布式锁

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Created by zzq on 2019/6/25.
 */
public class ZKLock implements Watcher {
    private ZooKeeper zk;
    //当前锁
    private String currentLock;
    //资源名称
    private String lockName;
    //锁根节点
    private String ROOT_LOCK = "/root_lock";
    //锁的各个资源根节点
    private String tmpRootLock;
    //由于zookeeper监听节点状态会立即返回,所以需要使用CountDownLatch(也可使用信号量等其他机制)
    private CountDownLatch latch;

    public ZKLock(String zkAddress, String lockName) {
        this.lockName = "" + System.nanoTime();
        try {
            zk = new ZooKeeper(zkAddress, 30000, this);
            createZNode(ROOT_LOCK, CreateMode.PERSISTENT);
            tmpRootLock = ROOT_LOCK + "/" + lockName;
            createZNode(tmpRootLock, CreateMode.PERSISTENT);//****zk临时节点下不能创建临时顺序节点
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void createZNode(String node, CreateMode mode) throws KeeperException, InterruptedException {
        //获取根节点状态
        Stat stat = zk.exists(node, false);
        //如果根节点不存在,则创建根节点,根节点类型为永久节点
        if (stat == null) {
            zk.create(node, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, mode);
        }
    }

    public void lock() {
        try {
            //在根节点下创建临时顺序节点,返回值为创建的节点路径
            currentLock = zk.create(tmpRootLock + "/" + lockName, new byte[0],
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            //获取根节点下的所有临时顺序节点,不设置监视器
            List<String> children = zk.getChildren(tmpRootLock, false);
            //对根节点下的所有临时顺序节点进行从小到大排序
            children.sort(null);
            //判断当前节点是否为最小节点,如果是则获取锁,若不是,则找到自己的前一个节点,监听其存在状态
            int curIndex = children.indexOf(currentLock.substring(currentLock.lastIndexOf("/") + 1));
            if (curIndex != 0) {
                //获取当前节点前一个节点的路径
                String prev = children.get(curIndex - 1);
                //监听当前节点的前一个节点的状态,null则节点不存在
                Stat stat = zk.exists(tmpRootLock + "/" + prev, true);
                //此处再次判断该节点是否存在
                if (stat != null) {
                    latch = new CountDownLatch(1);
                    //进入等待锁状态
                    latch.await();
                    latch = null;
                }
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //释放锁
    public void unlock() {
        try {
            //删除创建的节点
            zk.delete(currentLock, -1);
            List<String> children = zk.getChildren(tmpRootLock, false);
            if (children.size() == 0) {
                zk.delete(tmpRootLock, -1);
                //关闭zookeeper连接
                zk.close();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
        currentLock = null;
    }

    @Override
    public void process(WatchedEvent event) {
        if (this.latch != null) {
            latch.countDown();
        }
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 7; i++) {
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    ZKLock lock = new ZKLock("10.10.210.123:2181", "lock");
//                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                    lock.lock();
//                }
//            }).start();
        }
        ZKLock lock = new ZKLock("10.10.210.123:2181", "L1");
        lock.lock();

        ZKLock lock1 = new ZKLock("10.10.210.123:2181", "L2");
        lock1.lock();
        lock1.unlock();

        lock.unlock();
        String uu = "";
    }
}

原文地址:https://www.cnblogs.com/zzq-include/p/11083537.html

时间: 2024-10-29 09:48:05

基于zk“临时顺序节点“的分布式锁的相关文章

基于redis集群实现的分布式锁,可用于秒杀商品的库存数量管理,有測试代码(何志雄)

转载请标明出处. 在分布式系统中,常常会出现须要竞争同一资源的情况,本代码基于redis3.0.1+jedis2.7.1实现了分布式锁. redis集群的搭建,请见我的另外一篇文章:<><redis3.0.1集群环境搭建> 可用于比如秒杀系统中的商品库存的管理.付完整代码及測试用例. package com.gaojiasoft.gaojiaRedis; import java.util.UUID; import java.util.concurrent.LinkedBlockin

基于zookeeper实现分布式锁

一.分布式锁介绍 分布式锁主要用于在分布式环境中保护跨进程.跨主机.跨网络的共享资源实现互斥访问,以达到保证数据的一致性. 线程锁:大家都不陌生,主要用来给方法.代码块加锁.当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码.当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段.但是,其余线程是可以访问该对象中的非加锁代码块的. 进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为

【转】浅谈分布式锁

前言 随着互联网技术的不断发展,数据量的不断增加,业务逻辑日趋复杂,在这种背景下,传统的集中式系统已经无法满足我们的业务需求,分布式系统被应用在更多的场景,而在分布式系统中访问共享资源就需要一种互斥机制,来防止彼此之间的互相干扰,以保证一致性,在这种情况下,我们就需要用到分布式锁. 分布式一致性问题 首先我们先来看一个小例子: 假设某商城有一个商品库存剩10个,用户A想要买6个,用户B想要买5个,在理想状态下,用户A先买走了6了,库存减少6个还剩4个,此时用户B应该无法购买5个,给出数量不足的提

zookeeper(4)--zookeeper分布式锁原理

目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项.”所以,很多系统在设计之初就要对这三者做出取舍.在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即

分布式锁与实现(二)——基于ZooKeeper实现

引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. ZooKeeper的架构通过冗余服务实现高可用性.因此,如果第一次无应答,客户端就可以询问另一台ZooKeeper主机.ZooKeeper节点将它们的数据存储于一个分层的命名空间,非常类似于一个文件系统或一个前缀树结构.客户端可以在节点读写,

spring boot 定时任务基于zookeeper的分布式锁实现

基于ZooKeeper分布式锁的流程 在zookeeper指定节点(locks)下创建临时顺序节点node_n 获取locks下所有子节点children 对子节点按节点自增序号从小到大排序 判断本节点是不是第一个子节点,若是,则获取锁:若不是,则监听比该节点小的那个节点的删除事件 若监听事件生效,则回到第二步重新进行判断,直到获取到锁 具体实现 添加Maven依赖: <?xml version="1.0" encoding="UTF-8"?> <

基于redis的分布式锁实现

关于分布式锁 很久之前有讲过并发编程中的锁并发编程的锁机制:synchronized和lock.在单进程的系统中,当存在多个线程可以同时改变某个变量时,就需要对变量或代码块做同步,使其在修改这种变量时能够线性执行消除并发修改变量.而同步的本质是通过锁来实现的.为了实现多个线程在一个时刻同一个代码块只能有一个线程可执行,那么需要在某个地方做个标记,这个标记必须每个线程都能看到,当标记不存在时可以设置该标记,其余后续线程发现已经有标记了则等待拥有标记的线程结束同步代码块取消标记后再去尝试设置标记.

分布式锁的实现【基于ZooKeeper】

引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护.域名服务.分布式同步.组服务等. ZooKeeper的架构通过冗余服务实现高可用性.因此,如果第一次无应答,客户端就可以询问另一台ZooKeeper主机.ZooKeeper节点将它们的数据存储于一个分层的命名空间,非常类似于一个文件系统或一个前缀树结构.客户端可以在节点读写,

基于redis和zookeeper的分布式锁实现方式

先来说说什么是分布式锁,简单来说,分布式锁就是在分布式并发场景中,能够实现多节点的代码同步的一种机制.从实现角度来看,主要有两种方式:基于redis的方式和基于zookeeper的方式,下面分别简单介绍下这两种方式: 一.基于redis的分布式锁实现 1.获取锁 redis是一种key-value形式的NOSQL数据库,常用于作服务器的缓存.从redis v2.6.12开始,set命令开始变成如下格式: SET key value [EX seconds] [PX milliseconds] [