利用ZK原生客户端实现分布式锁

利用zookeeper原生客户端实现分布式锁:

       1.全部客户端在zk服务端创建同一个节点,但是只有一节客户端会创建成功,其余节点监听locks节点,如下图:


当节点删除后触发每个客户端向服务端创建节点,但是却只有一个客户端会创建成功,产生羊群效应,可以利用zk的临时有序节点特性,于是就有了第二种做法。

    2.利用zk的临时有序节点特性,每个客户端向同一个节点下创建临时有序节点,但是最小的节点会获取锁,每个节点监听对应的上一个节点。如下图:

对应代码:

public class DistributedLock implements Lock, Watcher {

    /**
 * zk客户端
 */
 private ZooKeeper zk;
 //当前节点
 private String CURRENT_LOCk;

 //等待的当前节点前一个节点
 private String WAIT_LOCK;

 private CountDownLatch countDownLatch;


 //根节点
 private String ROOT_LOCK = "/lock";

 public DistributedLock() {
        try {
            zk = new ZooKeeper("192.168.93.132:2181", 5000, this);
// Thread.sleep(10000);
 //判断根节点是否存在
 Stat stat = zk.exists(ROOT_LOCK, false);
 if (null == stat) {
                //创建根节点为永久
 zk.create(ROOT_LOCK, "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
 }

        } catch (IOException e) {
            e.printStackTrace();
 } catch (InterruptedException e) {
            e.printStackTrace();
 } catch (KeeperException e) {
            e.printStackTrace();
 }
    }

    @Override
 public void lock() {
        if (this.tryLock()) {
            //表示获取锁成功
 System.out.println(Thread.currentThread().getName() + "->" + CURRENT_LOCk + "获取锁成功");
 return;
 }

        //等待获取锁
 try {
            if (StringUtils.isNotEmpty(WAIT_LOCK)) {
                waitForLock(WAIT_LOCK);
 }

        } catch (KeeperException e) {
            e.printStackTrace();
 } catch (InterruptedException e) {
            e.printStackTrace();
 }
    }

    //监听比自己小的上一个节点状态,如果上一个节点删除关闭会话了,则触发监控当前节点获取锁
 private void waitForLock(String waitLock) throws KeeperException, InterruptedException {
        Stat stat = zk.exists(waitLock, true);
 if (stat != null) {
            System.out.println(Thread.currentThread().getName() + "->" + "等待" + waitLock + "释放锁");
 //当前节点的上一个节点还存在
 countDownLatch = new CountDownLatch(1);
 //等待
 countDownLatch.await();
 System.out.println(Thread.currentThread().getName() + "->" + "获取锁成功");
 }
    }

    @Override
 public void lockInterruptibly() throws InterruptedException {

    }

    @Override
 public boolean tryLock() {
        try {
            //创建临时有序节点
 CURRENT_LOCk = zk.create(ROOT_LOCK + "/", "0".getBytes(),
 ZooDefs.Ids.OPEN_ACL_UNSAFE,
 CreateMode.EPHEMERAL_SEQUENTIAL);
 //获取所有节点
 List<String> childres = zk.getChildren(ROOT_LOCK, false);

 //创建一个有序的set
 SortedSet<String> sortedSet = new TreeSet<>();
 for (String children : childres) {
                sortedSet.add(ROOT_LOCK + "/" + children);
 }

            //获取最小的节点
 String firstNode = sortedSet.first();
 //如果最小的节点等于当前节点,表示获取到了锁,并且不需要监控上一个节点
 if (CURRENT_LOCk.equals(firstNode)) {
                return true;
 }

            //获取比当前节点小的节点的数据,不包含当前节点
 SortedSet<String> lessThenMe = ((TreeSet<String>) sortedSet).headSet(CURRENT_LOCk);
 //如果有比自己小的节点
 if (!lessThenMe.isEmpty()) {
                //获取比当前节点更小的节点的最后一个节点
 WAIT_LOCK = lessThenMe.last();
 }

        } catch (KeeperException e) {
            e.printStackTrace();
 } catch (InterruptedException e) {
            e.printStackTrace();
 }

        return false;
 }

    @Override
 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
 }

    @Override
 public void unlock() {
        System.out.println(Thread.currentThread().getName() + "->释放锁");
 try {
            zk.delete(CURRENT_LOCk, -1);
 CURRENT_LOCk = null;
 zk.close();
 } catch (Exception e) {
            e.printStackTrace();
 }

    }

    @Override
 public Condition newCondition() {
        return null;
 }

    @Override
 public void process(WatchedEvent watchedEvent) {
        //如果上一个节点删除,触发watch
 if (countDownLatch != null) {
            countDownLatch.countDown();
 }
    }
}

测试代码:

public static void main(String[] args) throws IOException {
    CountDownLatch countDownLatch = new CountDownLatch(10);

 for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            try {
                countDownLatch.await();
 DistributedLock distributedLock = new DistributedLock();
 distributedLock.lock();
 } catch (Exception e) {
                e.printStackTrace();
 }

        },"Thread-"+i).start();
 countDownLatch.countDown();
 }
    System.in.read();

}

最后对应的线程4获取到了锁。

 

当然使用Curator很方便的就会实现基于zk的分布式锁。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值