zookeeper实现分布式锁

最近做一个RPC的框架,注册中心用的zk,为了给服务端每个提供服务的method都给编号,用到了分布式锁,正好就用zk实现了。
zookeeper实现的分布式锁我所知的有两种:
1.一种是利用zookeeper在创建子节点时候会保证对于一个znode只有一个客户端会创建成功的特性来实现的排他锁。
2.另一种就是利用zookeeper创建一系列的顺序节点,将这些节点排好序后,当前第一个节点获取锁,其它的节点(监测节点)依次的对它前一个节点(前节点)添加watcher,前节点删除时候,监测节点收到通知,此时监测节点获取到锁,进行操作后删除本节点,释放锁,这种锁称为共享锁。
以下就是一个共享锁的简单实现

package com.qiyi.rpc.zookeeper;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class DistributedLock implements Watcher {

    private CountDownLatch countDown;

    private static String lockRoot = "/qiyiLock";

    /** 上一个等待锁 **/
    private String beforeLock;

    private static ZooKeeper zk;

    /** 本节点 **/
    private String selfLock;

    private static Logger logger = LoggerFactory
            .getLogger(DistributedLock.class);

    @Override
    public void process(WatchedEvent event) {
        logger.info("节点:{}收到通知", selfLock);
        if (this.countDown != null) {
            this.countDown.countDown();
        }
    }

    public void lock() {
        if (tryLock()) {
            unlock();
        } else {
            if (wait(beforeLock, null)) {
                unlock();
            }
        }
    }

    public void unlock() {
        try {
            Thread.sleep(1000);
            logger.info("thread:{},释放锁,删除节点:{}",
                    Thread.currentThread().getId(), selfLock);
            zk.delete(lockRoot + "/" + selfLock, -1);
            selfLock = null;
            // zk.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    public boolean tryLock() {

        String lockName = "qiyiLocks-";

        try {
            /** 创建本节点 **/
            selfLock = zk.create(lockRoot + "/" + lockName, new byte[0],
                    ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.EPHEMERAL_SEQUENTIAL);
            selfLock = selfLock.substring(selfLock.lastIndexOf("/") + 1);
            logger.info("thread:{},创建锁节点:{}", Thread.currentThread().getId(),
                    selfLock);
            /** 获取根节点下子节点列表 **/
            List<String> childNodes = zk.getChildren(lockRoot, false);

            /** 将锁下面的子节点列表排序 **/
            Collections.sort(childNodes);
            logger.info("thread:{},获取到子节点列表:{}",
                    Thread.currentThread().getId(),
                    JSONObject.toJSONString(childNodes));

            int selfIndex = childNodes.indexOf(selfLock);
            if (selfIndex == 0) {
                logger.info("thread:{},当前节点是锁节点:{}", Thread.currentThread()
                        .getId(), selfLock);
                return true;
            } else if (selfIndex < 0) {
                return false;
            }

            beforeLock = childNodes.get(selfIndex - 1);
            logger.info("获取到上一个节点:{},本节点:{}", beforeLock, selfLock);

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

        return false;
    }

    public boolean wait(String beforeLock, Long timeout) {

        /** 添加watcher **/
        try {
            logger.info("监控节点:{},本节点:{}", lockRoot + "/" + beforeLock, selfLock);
            Stat stat = zk.exists(lockRoot + "/" + beforeLock, this);
            if (stat != null) {
                this.countDown = new CountDownLatch(1);
                if (timeout != null) {
                    this.countDown.await(timeout, TimeUnit.MILLISECONDS);
                } else {
                    this.countDown.await();
                }
            }
            return true;
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return false;
    }

    public static void initConnect() {
        try {
            zk = new ZooKeeper("192.168.1.111:2181", 5000, null);

            /** 创建锁节点 **/
            logger.info("创建根节点:{}", lockRoot);
            zk.create(lockRoot, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService e = Executors.newFixedThreadPool(100);
        DistributedLock.initConnect();
        for (int i = 0; i < 100; i++) {
            Runnable r = new Runnable() {

                @Override
                public void run() {

                    DistributedLock d = new DistributedLock();
                    d.lock();
                }
            };
            e.execute(r);
        }

        Thread.sleep(Long.MAX_VALUE);

    }

}

下面是部分结果:
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值