• 分布式锁的解决方案


    分布式锁的要求:

    a:互斥

    b:宕机避免死锁

    c:只能自己解锁

    d 能具备公平性最好

    1 数据库版本

    https://blog.csdn.net/linsongbin1/article/details/79444274 

    2 redis

    3zookeeper

    a:pom文件

    <!-- 原生zk支持-->
     <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.3.6</version>
            </dependency>
    <!-- zkclient原生客户端支持-->
            <dependency>
                <groupId>com.github.sgroschupf</groupId>
                <artifactId>zkclient</artifactId>
                <version>0.1</version>
            </dependency>

    b:必要参数采用yml配置注入

    zklock:
      url: 127.0.0.1:2181
      rootPath: /newlock17

    c: 创建锁工具类

    要点介绍:

    1:实现lock接口,开闭原则

    2:构造函数中实例化ZkClient

    3:  在根节点下创建临时顺序节点记得加分隔符“/”:

    package com.test.domi.common.utils.lock;
    
    import org.I0Itec.zkclient.IZkDataListener;
    import org.I0Itec.zkclient.ZkClient;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    
    public class ZKlock implements Lock {
    
        private ZkClient zkClient;
        private String rootPath;
        private String currentPath;
        private String beforePath;
    
        public ZKlock(String url,String rootPath){
            this.rootPath = rootPath;
            zkClient = new ZkClient(url);
            if (!zkClient.exists(rootPath)) {
                try {
                    zkClient.createPersistent(rootPath);
                } catch (RuntimeException e) {
                }
            }
        }
    
        @Override
        public boolean tryLock() {
            if (currentPath == null) {
                currentPath = zkClient.createEphemeralSequential(rootPath + "/","aaa");
            }
            List<String> childrens = zkClient.getChildren(rootPath);
            Collections.sort(childrens);
            if (currentPath.equals(rootPath + "/" + childrens.get(0))) {
                return true;
            }else{
                int curIndex = childrens.indexOf(currentPath.substring(rootPath.length() + 1));
                beforePath = rootPath + "/" + childrens.get(curIndex - 1);
            }
            return false;
        }
    
        @Override
        public void lock() {
            if (!tryLock()) {
                waiForLock();
                lock();
            }
        }
    
        @Override
        public void unlock() {
            zkClient.delete(currentPath);
        }
    
        private void waiForLock(){
            CountDownLatch cdl = new CountDownLatch(1);
            IZkDataListener listener = new IZkDataListener() {
                @Override
                public void handleDataChange(String s, Object o) throws Exception {
                }
                @Override
                public void handleDataDeleted(String s) throws Exception {
                    cdl.countDown();
                }
            };
            zkClient.subscribeDataChanges(beforePath,listener);
            if (zkClient.exists(beforePath)) {
                try {
                    cdl.await();
                } catch (InterruptedException e) {
                }
            }
            zkClient.unsubscribeDataChanges(beforePath,listener);
        }
    
        @Override
        public void lockInterruptibly() throws InterruptedException {
        }
    
        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return false;
        }
    
        @Override
        public Condition newCondition() {
            return null;
        }
    
    }
    currentPath = zkClient.createEphemeralSequential(rootPath + "/","aaa");

    d: 将锁工具类交给Spring管理,这样就不需要每次new的时候传入客户端的连接ip,一次注入终生受用,

    但是切记@Scope为多例,因为ZKLock里面的全局变量不能再多线程共享。

    package com.test.domi.config;
    
    import com.test.domi.common.utils.lock.ZKlock;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Scope;
    
    @Configuration
    public class ZkLockConfig {
    
        @Value("${zklock.rootPath}")
        private String rootPath;
        @Value("${zklock.url}")
        private String url;
    
        @Bean
        @Scope("prototype")
        public ZKlock getZKlock(){
            return new ZKlock(url,rootPath);
        }
    }

    e : 使用方式:

    要点:

    1- zklock.unlock(); 一般要放在finally中
    2- 重入之后一般需要判断业务是否执行过,已经执行过的应立即退出
    
    
    package com.test.domi.controller;

    import com.test.domi.common.utils.SpringContextUtil;
    import com.test.domi.common.utils.lock.ZKlock;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;


    @RestController
    @RequestMapping("/zk")
    public class ZKController {

    private int k = 1;

    @GetMapping("/lock")
    public Boolean getLock() throws Exception{


    for (int i = 0; i < 50; i++) {
    new Thread(new Runnable() {
    @Override
    public void run() {
    ZKlock zklock = SpringContextUtil.getBean(ZKlock.class);
    zklock.lock();
    try {
    System.out.println(Thread.currentThread().getName() + "获得锁,生成唯一的单据编号" + k++);
    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    zklock.unlock();
    }
    }
    }).start();
    }

    return true;
    }
    }
     
  • 相关阅读:
    结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂
    [转]Eclipse插件开发之基础篇(5) 制作OSGi Bundle
    [转]Eclipse插件开发之基础篇(4) OSGi框架
    [转]Eclipse插件开发之基础篇(3) 插件的测试与调试
    [转]Eclipse插件开发之基础篇(2) 第一个Eclipse插件
    [转]Eclipse插件开发之基础篇(1) 插件开发的基础知识
    深入理解JVM虚拟机(二):JDK 内存类的异常分析
    [收藏]Dubbo官方资料
    [转]JVM系列五:JVM监测&工具[整理中]
    [转]JVM系列四:生产环境参数实例及分析【生产环境实例增加中】
  • 原文地址:https://www.cnblogs.com/domi22/p/9746181.html
Copyright © 2020-2023  润新知