美文网首页
zk分布式锁

zk分布式锁

作者: 指尖架构141319 | 来源:发表于2019-11-20 14:34 被阅读0次

1.jdk锁

lock、synchronized、reentracklock等jdk自带锁,只能在同一个jvm中起作用,无法解决分布式多任务竞争共享资源的问题

2. 分布式锁对比

image.png

3.模板方法实现

tryLock,waitLock,unLock

4.获取锁流程

image.png

5.代码实现

  • 创建锁类(获取、阻塞、释放锁)
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
* @Description: zk获取、阻塞、释放锁
* @Author: liangyunbo
* @Date: 2019/11/20 9:30 AM
*/
public class ZookeeperDistrbuteLock_  {

    private CountDownLatch countDownLatch= null;

    // zk连接地址
    private static final String CONNECTSTRING = "172.16.223.132:2181";
    // 创建zk连接
    protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
    //设置路径
    protected static final String PATH2 = "/lock";
    //当前请求的节点前一个节点
    private String beforePath;
    //当前请求的节点
    private String currentPath;

    public ZookeeperDistrbuteLock_() {
        if (!this.zkClient.exists(PATH2)) {
            this.zkClient.createPersistent(PATH2);
        }
    }

    /**
    * @Description: 获取锁
    * @Param: []
    * @Return: void
    * @Author: liangyunbo
    * @Date: 2019/11/20 1:43 PM
    */
    public void getLock() {
        if (tryLock()) {
            System.out.println("##获取lock锁的资源####");
        } else {
            waitLock();
            getLock();
        }
    }

    /**
     * @Description: 是否获取到锁
     * @Param: []
     * @Return: void
     * @Author: liangyunbo
     * @Date: 2019/11/20 9:57 AM
     */
    public boolean  tryLock() {
        //如果currentPath为空则为第一次尝试加锁,第一次加锁赋值currentPath
        if(currentPath == null || currentPath.length()<= 0){
            //创建一个临时顺序节点
            currentPath = this.zkClient.createEphemeralSequential(PATH2 + '/',"lock");
        }
        //获取所有临时节点并排序,临时节点名称为自增长的字符串如:0000000400
        List<String> childrens = this.zkClient.getChildren(PATH2);
        Collections.sort(childrens);

        if (currentPath.equals(PATH2 + '/'+childrens.get(0))) {//如果当前节点在所有节点中排名第一则获取锁成功
            return true;
        } else {//如果当前节点在所有节点中排名中不是排名第一,则获取前面的节点名称,并赋值给beforePath
            int wz = Collections.binarySearch(childrens,
                    currentPath.substring(PATH2.length()+1));
            beforePath = PATH2 + '/'+childrens.get(wz-1);
        }
        return false;

    }

    /**
    * @Description: 阻塞锁
    * @Param: []
    * @Return: void
    * @Author: liangyunbo
    * @Date: 2019/11/20 1:39 PM
    */
    public void waitLock() {
        IZkDataListener listener = new IZkDataListener() {

            public void handleDataDeleted(String dataPath) throws Exception {
                if(countDownLatch!=null){
                    countDownLatch.countDown();
                }
            }
            public void handleDataChange(String dataPath, Object data) throws Exception {
            }
        };
        //给排在前面的的节点增加数据删除的watcher,本质是启动另外一个线程去监听前置节点
        this.zkClient.subscribeDataChanges(beforePath, listener);
        if(this.zkClient.exists(beforePath)){
            countDownLatch=new CountDownLatch(1);
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.zkClient.unsubscribeDataChanges(beforePath, listener);
    }

    /**
    * @Description: 释放锁
    * @Param: []
    * @Return: void
    * @Author: liangyunbo
    * @Date: 2019/11/20 1:40 PM
    */
    public void unLock() {
        zkClient.delete(currentPath);
        zkClient.close();
    }
}
  • 调用类
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* @Description: 调用类
* @Author: liangyunbo
* @Date: 2019/11/20 2:33 PM
*/
public class OrderService_ implements Runnable {

    //全局订单id
    public static int count = 0;
    private ZookeeperDistrbuteLock_ lock = new ZookeeperDistrbuteLock_();

    /**
    * @Description: main
    * @Author: liangyunbo
    * @Date: 2019/11/20 2:29 PM
    */
    public static void main(String[] args) {
        System.out.println("####生成唯一订单号###");
        for (int i = 0; i < 50; i++) {
            new Thread( new OrderService_()).start();
        }
    }

    public void run() {
        try {
            lock.getLock();
            String number = getNumber();
            System.out.println(Thread.currentThread().getName() + ",生成订单ID:" + number);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unLock();
        }
    }

    /**
    * @Description: 生成订单id
    * @Author: liangyunbo
    * @Date: 2019/11/20 2:15 PM
    */
    public String getNumber() {
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        return simpt.format(new Date()) + "-" + ++count;
    }
}

相关文章

网友评论

      本文标题:zk分布式锁

      本文链接:https://www.haomeiwen.com/subject/xcgzbctx.html