当前位置: 首页 > news >正文

基于zookeeper实现分布式锁

什么是分布式锁

分布式锁一般用在分布式系统或者多个应用中,用来控制同一任务是否执行或者任务的执行顺序。在项目中,部署了多个tomcat应用,在执行定时任务时就会遇到同一任务可能执行多次的情况,我们可以借助分布式锁,保证在同一时间只有一个tomcat应用执行了定时任务

分布式锁有那些实现方案

 

1.使用数据库实现分布式锁(不推荐使用)

缺点:效率低,性能差、线程出现异常时,容易出现死锁

2.使用redis实现分布式锁

缺点:锁的失效时间难控制、容易产生死锁、非阻塞式、不可重入

3.使用zookeeper实现分布式锁

实现相对简单、可靠性强、使用临时节点,失效时间容易控制

4.springcloud内置实现全局锁:比较冷门,但是效率最高,实现简单,失效时间容易控制。

Zookeeper实现分布式锁原理

使用zookeeper创建临时序列节点来实现分布式锁,适用于顺序执行的程序,大体思路就是创建临时序列节点,找出最小的序列节点,获取分布式锁,程序执行完成之后此序列节点消失,通过watch来监控节点的变化,从剩下的节点的找到最小的序列节点,获取分布式锁,执行相应处理,依次类推。

Maven依赖

    <dependencies>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>
    </dependencies>

创建Lock接口

public interface Lock {
    //获取到锁的资源
    public void getLock();
    // 释放锁
    public void unLock();
}

 

 

 

创建ZookeeperAbstractLock抽象类

//将重复代码写入子类中..
public abstract class ZookeeperAbstractLock implements Lock {
    // zk连接地址
    private static final String CONNECTSTRING = "127.0.0.1:2181";
    // 创建zk连接
    protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
    protected static final String PATH = "/lock";

    public void getLock() {
        if (tryLock()) {
            System.out.println("##获取lock锁的资源####");
        } else {
            // 等待
            waitLock();
            // 重新获取锁资源
            getLock();
        }

    }

    // 获取锁资源
    abstract boolean tryLock();

    // 等待
    abstract void waitLock();

    public void unLock() {
        if (zkClient != null) {
            zkClient.close();
            System.out.println("释放锁资源...");
        }
    }

}

ZookeeperDistrbuteLock类

public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
    private CountDownLatch countDownLatch = null;

    @Override
    boolean tryLock() {
        try {
            zkClient.createEphemeral(PATH);
            return true;
        } catch (Exception e) {
//            e.printStackTrace();
            return false;
        }

    }

    @Override
    void waitLock() {
        IZkDataListener izkDataListener = new IZkDataListener() {

            public void handleDataDeleted(String path) throws Exception {
                // 唤醒被等待的线程
                if (countDownLatch != null) {
                    countDownLatch.countDown();
                }
            }
            public void handleDataChange(String path, Object data) throws Exception {

            }
        };
        // 注册事件
        zkClient.subscribeDataChanges(PATH, izkDataListener);
        if (zkClient.exists(PATH)) {
            countDownLatch = new CountDownLatch(1);
            try {
                countDownLatch.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 删除监听
        zkClient.unsubscribeDataChanges(PATH, izkDataListener);
    }

}

使用Zookeeper锁运行效果

public class OrderService implements Runnable {
    private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
    // 使用lock锁
    // private java.util.concurrent.locks.Lock lock = new ReentrantLock();
    private Lock lock = new ZookeeperDistrbuteLock();
    public void run() {
        getNumber();
    }
    public void getNumber() {
        try {
            lock.getLock();
            String number = orderNumGenerator.getNumber();
            System.out.println(Thread.currentThread().getName() + ",生成订单ID:" + number);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unLock();
        }
    }
    public static void main(String[] args) {
        System.out.println("####生成唯一订单号###");
//        OrderService orderService = new OrderService();
        for (int i = 0; i < 100; i++) {
            new Thread( new OrderService()).start();
        }
    }
}

 

转载于:https://www.cnblogs.com/andydong/p/10222939.html

相关文章:

  • 微信小程序之----接口调用方式
  • django 的后台管理
  • Vue 目录
  • 蒟蒻的作文
  • PLC之六部十层电梯整体框架
  • js实现数组去重的几种方法
  • MapReduce编程:词频统计
  • Python基础之文件
  • 使用vuepress搭建文档管理/博客
  • 什么是分布式系统,如何学习分布式系统
  • Dynamics CRM - 如何解决 Microsoft Dynamics CRM has encountered an error 弹窗的问题
  • python队列Queue
  • [转]让Linux进入虚拟机 Virtualenv
  • C++学习二十C++中函数重载的理解
  • vuex存储和本地存储(localstorage、sessionstorage)的区别
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • 【React系列】如何构建React应用程序
  • Angular4 模板式表单用法以及验证
  • angular组件开发
  • co模块的前端实现
  • ES6系列(二)变量的解构赋值
  • ES6之路之模块详解
  • HTML-表单
  • Java新版本的开发已正式进入轨道,版本号18.3
  • java正则表式的使用
  • jdbc就是这么简单
  • js中的正则表达式入门
  • mysql 数据库四种事务隔离级别
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • mysql外键的使用
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • REST架构的思考
  • Vue 2.3、2.4 知识点小结
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 来,膜拜下android roadmap,强大的执行力
  • 前端知识点整理(待续)
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 首页查询功能的一次实现过程
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 我从编程教室毕业
  • C# - 为值类型重定义相等性
  • UI设计初学者应该如何入门?
  • 如何用纯 CSS 创作一个货车 loader
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​linux启动进程的方式
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (办公)springboot配置aop处理请求.
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (论文阅读30/100)Convolutional Pose Machines
  • (南京观海微电子)——COF介绍
  • (一)80c52学习之旅-起始篇
  • (转载)CentOS查看系统信息|CentOS查看命令