1.实现原理

Zookeeper节点每个只能创建一个,多个创建会失败,临时节点每次关闭连接都会失效,获取锁则对应为创建临时节点,释放锁则关闭连接。,多JVM获取锁通过监听事件通知来获取锁

2. 实现代码

引入依赖

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

1.伪订单服务
OrderNumGenerator

package com.zou;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author WH
 * @version 1.0
 * @date 2020/2/15 10:01
 */
public class OrderNumGenerator {
    //生成订单号
    private static  int count = 0;

    public String getNumber() {
        try {
            Thread.sleep(200);
        } catch (Exception e) {

        }
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        return simpt.format(new Date()) + "-" + ++count;

    }
}
  1. 锁接口
    ZKLock
public interface ZKLock {
    //获取锁
    public void getLock();
    //释放锁
    public void unLock();
}
  1. 抽象类
    ZooKeeperAbstractLock
package com.zou;

import org.I0Itec.zkclient.ZkClient;

import java.util.concurrent.CountDownLatch;

/**
 * 模板方法设计模式抽离重复代码到子类
 * @author WH
 * @version 1.0
 * @date 2020/2/15 9:26
 */
public abstract class ZooKeeperAbstractLock implements ZKLock {

    private static final String CONNECTION = "49.233.150.105:2181";
    protected ZkClient zkClient = new ZkClient(CONNECTION);
    protected String lockPath = "/lockPath";
    protected CountDownLatch countDownLatch = null;
    /*
    * 获取锁
    * */
    @Override
    public void getLock() {
        //1. 连接zk,在zk上创建/lock节点,节点为临时节点
        //2. 如果节点创建成功,获取锁,否则等待
        if (tryLock()) {
            System.out.println("获取锁成功");
        } else {
            //3. 事件监听节点是否被删除,删除则重新获取锁资源
            waitLock();
            // 4.重新获取锁
            getLock();
        }

    }
    /**
     * 获取锁资源,成功返回true,否则false
     */
    abstract void waitLock();

    abstract boolean tryLock();

    /*
    * 释放锁
    * */
    @Override
    public void unLock() {
        //程序执行完毕关闭连接
        if (zkClient != null) {
            zkClient.close();
            System.out.println("释放锁成功");
        }

    }

}
  1. ZookeeperDistrbuteLock
package com.zou;

import org.I0Itec.zkclient.IZkDataListener;

import java.util.concurrent.CountDownLatch;

/**
 * @author WH
 * @version 1.0
 * @date 2020/2/15 9:38
 */
public class ZookeeperDistrbuteLock extends ZooKeeperAbstractLock {
    @Override
    void waitLock() {
        //监听事件通知
        IZkDataListener iZkDataListener = new IZkDataListener() {
            //节点修改
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

            //节点删除
            @Override
            public void handleDataDeleted(String s) throws Exception {
                if (countDownLatch != null) {
                    countDownLatch.countDown();
                }

            }
        };
        //注册事件
        zkClient.subscribeDataChanges(lockPath, iZkDataListener);
        // 如果节点存在
        if (zkClient.exists(lockPath)) {
            try {
                countDownLatch = new CountDownLatch(1);
                countDownLatch.await();
            } catch (Exception e) {
                e.printStackTrace();

            }
        }
        //删除事件  防止事件监听多次
        zkClient.unsubscribeDataChanges(lockPath, iZkDataListener);

    }

    @Override
    boolean tryLock() {
        try {
            //创建临时节点
            zkClient.createEphemeral(lockPath);
            return true;
        } catch (Exception e) {
            //如果临时节点创建失败
            return false;

        }
    }
}

  1. 测试类
    OrderService
package com.zou;

/**
 * @author WH
 * @version 1.0
 * @date 2020/2/15 9:58
 */
public class OrderService {
    private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
    private ZKLock zkLock = new ZookeeperDistrbuteLock();


    //获取订单号
    public void getNumber() {
        try {
            zkLock.getLock();
            String number = orderNumGenerator.getNumber();
            System.out.println("线程:" + Thread.currentThread().getName() + "生成订单号为:" + number);
        } catch (Exception e) {

        } finally {
            zkLock.unLock();
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() ->{
                //模拟多个JVM产生多个OrderService实例
                System.out.println("线程:" + Thread.currentThread().getName() + "启动");
                new OrderService().getNumber();
            }).start();
        }
    }
}

实现效果

在这里插入图片描述

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐