zookeeper实现分布式锁

package com.lishilin.javaapi.distributlock;

import org.apache.zookeeper.*;

import java.util.List;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class DistributeLock {
    private static final String ROOT = "/LOCKS"; //根节点

private ZooKeeper zooKeeper;

private int sessionTimeout; //会话超时时间

private String lockID;  //记录锁节点id

private byte[] data = {1,2,3};

private CountDownLatch countDownLatch = new CountDownLatch(1);

public DistributeLock() {
    zooKeeper = ZookeeperClient.getInstance();
    sessionTimeout = ZookeeperClient.getSessionTimeout();
}

public boolean lock() {
    try {
        lockID = zooKeeper.create(ROOT+"/",data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        System.out.println(Thread.currentThread().getName()+"->成功创建节点["+lockID+"]去竞争锁");
        List<String> children = zooKeeper.getChildren(ROOT, true);
        //从小到大排序
        SortedSet<String> sortedSet = new TreeSet();
        for (String child : children) {
            sortedSet.add(ROOT+"/"+child);
        }
        String first = sortedSet.first();
        if (lockID.equals(first)) {
            System.out.println(Thread.currentThread().getName()+"当前线程成功获得锁" +
                    "lock节点为["+lockID+"]");
            return true;
        }
        SortedSet<String> lessThanLockID = sortedSet.headSet(lockID);//获取比lockID小的所有的节点
        if(!lessThanLockID.isEmpty()) {
            String prevLockID = lessThanLockID.last();
            zooKeeper.exists(prevLockID,watchedEvent -> {
                if(watchedEvent.getType() == Watcher.Event.EventType.NodeDeleted) {
                    countDownLatch.countDown();
                }
            });
            countDownLatch.await(sessionTimeout, TimeUnit.MILLISECONDS);//超时或节点被删除
            System.out.println(Thread.currentThread().getName()+"当前线程成功获得锁lock节点为["+lockID+"]");
        }
        return true;
    } catch (KeeperException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return false;
}

public boolean unlock() {
    System.out.println(Thread.currentThread().getName()+"开始释放锁["+lockID+"]");
    try {
        zooKeeper.delete(lockID,-1);
        System.out.println(lockID+"成功被删除");
        return true;
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (KeeperException e) {
        e.printStackTrace();
    }
    return false;
}

public static void main(String[] args) {
    CountDownLatch countDownLatch = new CountDownLatch(10);
    Random random = new Random();
    for(int i=0;i<10;i++) {
        new Thread(()->{
            DistributeLock lock = null;
            try {
                lock = new DistributeLock();
                countDownLatch.countDown();
                countDownLatch.await();
                lock.lock();
                Thread.sleep(random.nextInt(500));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if(lock != null) {
                    lock.unlock();
                }
            }
        }).start();
    }
}
}

package com.lishilin.javaapi.distributlock;

import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

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

public class ZookeeperClient {

private static ZooKeeper zooKeeper;

private static String CONNECTION = "192.168.137.8:2181";

private static int sessionTimeout = 5000;

public static ZooKeeper getZooKeeper() {
    return zooKeeper;
}

public static void setZooKeeper(ZooKeeper zooKeeper) {
    ZookeeperClient.zooKeeper = zooKeeper;
}

public static String getCONNECTION() {
    return CONNECTION;
}

public static void setCONNECTION(String CONNECTION) {
    ZookeeperClient.CONNECTION = CONNECTION;
}

public static int getSessionTimeout() {
    return sessionTimeout;
}

public static void setSessionTimeout(int sessionTimeout) {
    ZookeeperClient.sessionTimeout = sessionTimeout;
}

public static ZooKeeper getInstance() {
    CountDownLatch countDownLatch = new CountDownLatch(1);
    try {
        zooKeeper = new ZooKeeper(CONNECTION,sessionTimeout,(watchedEvent)->{
            if (watchedEvent.getState()== Watcher.Event.KeeperState.SyncConnected) {
                countDownLatch.countDown();
            }
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return zooKeeper;
}
}

根据zookeeper临时节点有序节点特性实现分布式锁(公平锁)
新来一个线程竞争锁
1、首先将节点插入到zookeeper锁的根节点下(临时有序节点)
2、获得根节点下所有的孩子节点
3、遍历集合从小到大排序
4、判断当前节点是不是集合里最小的节点
4.1如果是获得锁
4.2如果不是执行下面逻辑
5、获取比当前节点小的所有节点的集合
5.1如果非空,获取集合中最后的节点(比当前节点小的最大的节点),监听这个节点,线程阻塞,如果被删除了,当前线程获取锁,超过超时时间也获得锁。
5.2如果为空,没有比当前线程的节点更小的节点了,当前线程获取锁

线程释放锁
直接删除节点即可。zookeeper临时节点的特性是客户端和zookeeper断开时,节点就被删除,如果使用持久节点,会出现客户端出现异常断开时,锁无法释放的结果

这里实现的是公平非重入锁,如果想实现非公平锁和重入锁,可以参考jdk源码JUC包下的ReentrantLock

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值