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基於臨時順序節點的分佈式鎖
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.