package com.yucong.zkClient;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
/**
* <li>基于临时顺序节点的分布式锁</li>
*/
public class EphemeralSequentialLock {
private static final String head = "/EphemeralSequential";
private static final String prefix = "/lock";
private static final String PATH = head + prefix;
private ZkClient zkClient = new ZkClient("127.0.0.1:2181"); // 在这里每一个线程都有自己的zkClient,用完需要关闭
private CountDownLatch latch = null;
private String beforePath;// 当前请求节点的前一个节点
private String currentPath;// 当前请求的节点
// 获得锁
public void getLock() {
if (tryLock()) {
System.out.println(Thread.currentThread().getName() + ": 获得锁");
} else {
// 等待临时节点被删除
waitLock();
// 继续获取锁
getLock();
}
}
// 释放锁
public void unLock() {
if (zkClient != null) {
System.out.println(Thread.currentThread().getName() + ": 释放锁");
zkClient.delete(currentPath);
zkClient.close();
}
}
private boolean tryLock() {
if (currentPath == null || currentPath.length() <= 0) {
currentPath = zkClient.createEphemeralSequential(PATH, "what");
}
List<String> children = zkClient.getChildren(head);
Collections.sort(children); // 此处必须排序
System.out.println("==============================================:" + children);
if (currentPath.equals(head + '/' + children.get(0))) {
return true;
} else {
int wz = Collections.binarySearch(children, currentPath.substring(head.length() + 1));
beforePath = head + '/' + children.get(wz - 1);
return false;
}
}
private void waitLock() {
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String datahead) throws Exception {
if (latch != null) {
latch.countDown();
}
}
@Override
public void handleDataChange(String datahead, Object data) throws Exception {}
};
// 注册事件
zkClient.subscribeDataChanges(beforePath, listener);
// 如果节点存,阻塞线程直到head被删除,触发handleDataDeleted事件
if (zkClient.exists(beforePath)) {
latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 删除监听
zkClient.unsubscribeDataChanges(beforePath, listener);
}
public static void main(String[] args) throws Exception {
int conut = 10;
CountDownLatch countDownLatch = new CountDownLatch(conut);
for (int i = 0; i < conut; i++) {
new Thread(new People(countDownLatch)).start();
}
countDownLatch.await(); // 打开所有线程
}
}
/**
* <li>模拟多用户</li>
*/
class People implements Runnable {
private EphemeralSequentialLock lock = new EphemeralSequentialLock();
private CountDownLatch countDownLatch = null;
public People(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
countDownLatch.countDown(); // 阻塞所有线程
lock.getLock();
int i = new Random().nextInt(3) + 1;
Thread.sleep(i * 1000);
System.out.println(Thread.currentThread().getName() + ": 开始睡眠" + i + "s");
} catch (Exception e) {
//
} finally {
lock.unLock();
}
}
}
zk基于临时顺序节点的分布式锁
最新推荐文章于 2023-04-27 15:39:51 发布