【zookeeper】利用zookeeper实现分布式锁


手写zookeeper分布式锁,测试生成订单编号

1.生成订单编号工具类

/**
 * TODO
 *
 * @author CSD
 * @date 2021-09-09 13:51
 * 订单编号工具类
 */
public class OrderNumCreateUtil {

    private static int number = 0;

    /**
     * 生成订单编号
     * @return
     */
    public String getNumber(){
        return String.valueOf(++number);
    }
}

2.订单业务类

/**
 * TODO
 * 订单业务类
 * @author CSD
 * @date 2021-09-09 13:54
 */
public class OrderService {
    private OrderNumCreateUtil orderNumCreateUtil = new OrderNumCreateUtil();

    private ZkLock zkLock = new ZkDistributedLock();
    public void getOrdNumber() {
        zkLock.zklock();
        try {
            String number = orderNumCreateUtil.getNumber();
            System.out.println("number = " + number);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            zkLock.zkUnlock();
        }
    }
}

3.zookeeper接口

/**
 * TODO
 *
 * @author CSD
 * @date 2021-09-09 14:05
 */
public interface ZkLock {

    public void zklock();
    public void zkUnlock();
}

4. 使用模板设计模式把共用的代码抽离父类

/**
 * TODO
 *
 * @author CSD
 * @date 2021-09-09 14:07
 */
public abstract class ZkAbstractTemplateLock implements ZkLock {

    protected String path = "/zkLock";
    protected CountDownLatch countDownLatch = null;
    public static final String ZKSERVER = "172.22.83.153:2181";
    public static final Integer TIME_OUT = 45 * 1000;
    ZkClient zkClient = new ZkClient(ZKSERVER,TIME_OUT);
    @Override
    public void zklock() {
        if(tryZkLock()){
            System.out.println("线程"+Thread.currentThread().getName()+":获得锁\n");
        }else{
            waitZkLock();
            zklock();
        }
    }

    public abstract void waitZkLock();

    public abstract boolean tryZkLock();

    @Override
    public void zkUnlock() {
        if (zkClient != null){
            zkClient.close();
        }
        System.out.println("线程"+Thread.currentThread().getName()+"释放锁\n\n");
    }
}

5.zk分布式锁具体的实现类

/**
 * TODO
 *
 * @author CSD
 * @date 2021-09-09 14:22
 */
public class ZkDistributedLock extends ZkAbstractTemplateLock{

    @Override
    public void waitZkLock() {
        IZkDataListener iZkDataListener = new IZkDataListener() {
            @Override
            public void handleDataChange(String dataPath, Object data)  {

            }

            @Override
            public void handleDataDeleted(String dataPath){
                if (countDownLatch != null){
                    countDownLatch.countDown();
                }
            }
        };

        zkClient.subscribeDataChanges(path,iZkDataListener);
        if (zkClient.exists(path)){
            countDownLatch = new CountDownLatch(1);
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        zkClient.unsubscribeDataChanges(path,iZkDataListener);
    }

    @Override
    public boolean tryZkLock() {
        try {
            zkClient.createEphemeral(path);
            return true;
        } catch (Exception e){
            return false;
        }
    }
}

6.开启10个线程测试

/**
 * TODO
 *
 * @author CSD
 * @date 2021-09-09 13:57
 */
public class Client {
    public static void main(String[] args) {
        for (int i = 0; i < 50; i++) {
            new Thread(()->{
                new OrderService().getOrdNumber();
            },String.valueOf(i)).start();
        }
    }
}

7.运行结果

线程6:获得锁

number = 1
线程6释放锁


线程1:获得锁

number = 2
线程1释放锁


线程5:获得锁

number = 3
线程5释放锁


线程8:获得锁

number = 4
线程8释放锁


线程2:获得锁

number = 5
线程2释放锁


线程4:获得锁

number = 6
线程4释放锁


线程0:获得锁

number = 7
线程0释放锁


线程7:获得锁

number = 8
线程7释放锁


线程3:获得锁

number = 9
线程3释放锁


线程9:获得锁

number = 10
线程9释放锁

8.所用的maven依赖


     com.github.sgroschupf
     zkclient
     0.1