package com.yucong.zkClient;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
/**
* <li>基於臨時節點的分佈式鎖</li>
*/
public class EphemeralLock {
private static final String PATH = "/EphemeralLock";
private ZkClient zkClient = new ZkClient("127.0.0.1:2181");// 在這裏每一個線程都有自己的zkClient,用完需要關閉
private CountDownLatch latch = null;
// 獲得鎖
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(PATH);
zkClient.close();
}
}
private boolean tryLock() {
try {
zkClient.createEphemeral(PATH);
return true;
} catch (Exception e) {
return false;
}
}
private void waitLock() {
IZkDataListener listener = new IZkDataListener() {
@Override
public void handleDataDeleted(String dataPath) throws Exception {
if (latch != null) {
latch.countDown();
}
}
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {}
};
// 註冊事件
zkClient.subscribeDataChanges(PATH, listener);
// 如果節點存,阻塞線程直到PATH被刪除,觸發handleDataDeleted事件
if (zkClient.exists(PATH)) {
latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 刪除監聽
zkClient.unsubscribeDataChanges(PATH, 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 Person(countDownLatch)).start();
}
countDownLatch.await(); // 打開所有線程
}
}
/**
* <li>模擬多用戶</li>
*/
class Person implements Runnable {
private EphemeralLock lock = new EphemeralLock();
private CountDownLatch countDownLatch = null;
public Person(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基於臨時節點的分佈式鎖
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.