基于ZK实现分布式锁

如何基于zk实现分布式锁?

1: 有序节点

2:临时节点:

3:watcher 机制;

1,2点不做具体描述,具体操作查看官网文档

基于ZK原生API和 Curator客户端的watcher机制:  https://blog.csdn.net/chenshaohua12345/article/details/86367617

还有一种比较简单的实现方法:Curator客户端

直接上代码:  基于ZK实现的分布式锁

package Zookeeper.zookeeper.Distributed;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;


/**
 * Created by Csh on 2019/1/14.
 */
public class DistributedLockWithZK implements Lock, Watcher {

    private ZooKeeper zooKeeper = null;
    private String ROOT_LOCKS = "/lock";  //定义根节点
    private String WAIT_LOCK;//等待前一个锁
    private String CURRENT_LOCK; //表示当前的锁
    private CountDownLatch countDownLatch;


    /**
     * 初始化zk
     */
    public DistributedLockWithZK() {
        try {
            zooKeeper = new ZooKeeper("47.93.63.243:2181", 4000, this);
            //判断根节点是否存在
            Stat stat = zooKeeper.exists(ROOT_LOCKS, false);
            if (stat == null) {
                zooKeeper.create(ROOT_LOCKS, "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() + ">" + "获得锁成功!");
            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 = zooKeeper.exists(prev, true);
        if (stat != null) {
            System.out.println(Thread.currentThread().getName() + ">等待锁---" + CURRENT_LOCK + "/" + prev + "释放锁!");
            countDownLatch = new CountDownLatch(1);
            countDownLatch.await();
            //todo 当watcher 触发后还需要再次判断当前等待的节点时候是最小的
            System.out.println(Thread.currentThread().getName() + ">获得锁");
        }
        return true;
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    /**
     * 尝试获得所
     *
     * @return
     */
    @Override
    public boolean tryLock() {
        try {
            CURRENT_LOCK = zooKeeper.create(ROOT_LOCKS + "/", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println(Thread.currentThread().getName() + ">" + CURRENT_LOCK + "," + "尝试竞争锁!!");
            //获得所有节点下面的子节点;
            List<String> childrens = zooKeeper.getChildren(ROOT_LOCKS, false);
            //定义一个集合进行排序
            SortedSet<String> sortedSet = new TreeSet<>();
            for (String children : childrens) {
                sortedSet.add(ROOT_LOCKS + "/" + children);
            }
            //获得当前节点中的最小的子节点;
            String firstNode = sortedSet.first();
            SortedSet<String> lessThenMe = ((TreeSet<String>) sortedSet).headSet(CURRENT_LOCK);
            //通过当前节点与最小节点进行比较 , 如果相等则获取所成功;
            if (CURRENT_LOCK.equals(firstNode)) {
                return true;
            }
            ///获得比当前节点更小的最后一个节点,设置给WAIT_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()+"释放锁"+CURRENT_LOCK);
        try {
            //设置version为-1 不管什么情况都要删除
            zooKeeper.delete(CURRENT_LOCK,-1);
            CURRENT_LOCK=null;
            zooKeeper.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }


    }

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

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

    }
}

main方法调用:

package Zookeeper.zookeeper.Distributed;


import java.io.IOException;
import java.util.concurrent.CountDownLatch;


/**
 * Created by Csh on 2019/1/14.
 */
public class DistributedLockWithZKDemo {
    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();
                    DistributedLockWithZK distributedLockWithZK = new DistributedLockWithZK();
                    distributedLockWithZK.lock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

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

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值