zookeeper原生API实现分布式锁

原生API实现分布式锁

原理
这里写图片描述
每个客户端都往zookeeper上创建一个临时有序节点,注册完后,取/locks下所有节点中最小的节点,则创建该最小节点的客户端拿到锁。如果当前最小节点是/lock_seq1,那么/lock_seq2边监听/lock_seq1边阻塞等待,当/lock_seq1被删除后,/lock_seq2节点的客户端获得锁,以此类推。

代码

public class DistributedLock implements Lock,Watcher{

    private ZooKeeper zk=null;
    private String ROOT_LOCK="/locks";//定义根节点
    private String WAIT_LOCK;//等待前一个锁
    private String CURRENT_LOCK;//当前的锁

    private CountDownLatch countDownLatch;

    public DistributedLock() {
        try {
            zk=new ZooKeeper("192.168.3.140:2181",4000,this);
            //判断根节点是否存在
            Stat stat=zk.exists(ROOT_LOCK,false);
            if(stat==null){
                zk.create(ROOT_LOCK,"0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void lock() {
        if(this.tryLock()){//如果获得锁成功
            System.out.println(Thread.currentThread().getName()+"->"+CURRENT_LOCK+"->获得锁成功");
            return;
        }
        try {
            waitForLock(WAIT_LOCK);//没有获得锁,继续等待
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private boolean waitForLock(String prev) throws KeeperException, InterruptedException {
        Stat stat=zk.exists(prev,true);//监听当前节点的上一个节点
        if(stat!=null){
            System.out.println(Thread.currentThread().getName()+"->等待锁"+ROOT_LOCK+"/"+prev+"释放");
            countDownLatch=new CountDownLatch(1);
            countDownLatch.await();
            System.out.println(Thread.currentThread().getName()+"->获得锁成功");
        }
        return true;
    }

    public void lockInterruptibly() throws InterruptedException {

    }

    public boolean tryLock() {
        try {
            //创建临时有序节点
            CURRENT_LOCK=zk.create(ROOT_LOCK+"/","0".getBytes(),
                    ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println(Thread.currentThread().getName()+"->"+CURRENT_LOCK+" 尝试竞争锁");
            //例:children=[0000000260...000000000269]
            List<String> children=zk.getChildren(ROOT_LOCK,false);//获取根节点下所有子节点,这里的watcher设为false,因为不需要去监听
            //例:sortedSet=[/locks/0000000260.../locks/0000000260]
            SortedSet<String> sortedSet=new TreeSet();//定义一个有序集合进行排序
            for(String child:children){
                sortedSet.add(ROOT_LOCK+"/"+child);
            }
            //例:firstNode=/locks/0000000260
            String firstNode=sortedSet.first();//获得当前所有子节点中最小的节点
            //获取比当前节点更小的节点
            //例:CURRENT_LOCK=/locks/0000000262 lessThenMe=[/locks/0000000260,/locks/0000000261]
            SortedSet<String> lessThenMe=((TreeSet<String>)sortedSet).headSet(CURRENT_LOCK);
            if(CURRENT_LOCK.equals(firstNode)){//当前的节点和子节点中最小的节点比较,如果相等,则获得锁
                return true;
            }
            if(!lessThenMe.isEmpty()){
                //例:WAIT_LOCK=/locks/0000000261
                WAIT_LOCK=lessThenMe.last();//获得比当前节点更小的最后一个节点,设置给WAIT_LOCK
            }
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return false;
    }

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

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

    public Condition newCondition() {
        return null;
    }

    public void process(WatchedEvent watchedEvent) {
        if(this.countDownLatch!=null){
            this.countDownLatch.countDown();
        }
    }
}

测试运行

//开启10个线程,并且同时往zookeeper上注册节点
public class DistributedLockTest {

    public static void main(String[] args) throws IOException {
        final CountDownLatch countDownLatch=new CountDownLatch(10);
        for(int i=0;i<10;i++){
            new Thread(new Runnable() {
                public void run() {
                    try {
                        countDownLatch.await();
                        //10个线程一起并发执行以下代码
                        DistributedLock distributedLock=new DistributedLock();
                        distributedLock.lock();//当前线程获得锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            },"Thread-"+i).start();
            countDownLatch.countDown();
        }
        System.in.read();
    }
}

执行结果
Thread-5->/locks/0000000301 尝试竞争锁
Thread-0->/locks/0000000300 尝试竞争锁
Thread-3->/locks/0000000303 尝试竞争锁
Thread-7->/locks/0000000305 尝试竞争锁
Thread-9->/locks/0000000306 尝试竞争锁
Thread-6->/locks/0000000304 尝试竞争锁
Thread-1->/locks/0000000309 尝试竞争锁
Thread-2->/locks/0000000302 尝试竞争锁
Thread-4->/locks/0000000307 尝试竞争锁
Thread-8->/locks/0000000308 尝试竞争锁
Thread-0->/locks/0000000300->获得锁成功
Thread-4->等待锁/locks//locks/0000000306释放
Thread-3->等待锁/locks//locks/0000000302释放
Thread-7->等待锁/locks//locks/0000000304释放
Thread-5->等待锁/locks//locks/0000000300释放
Thread-1->等待锁/locks//locks/0000000308释放
Thread-8->等待锁/locks//locks/0000000307释放
Thread-9->等待锁/locks//locks/0000000305释放
Thread-2->等待锁/locks//locks/0000000301释放
Thread-6->等待锁/locks//locks/0000000303释放

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值