Zookeeper實現分佈式鎖
**
* 實現分佈式環境下同步鎖的實現
*
* @author hao.wang
* @date 2017/1/20 15:43
*/
public class DistributeLockDemo implements Watcher {
ZooKeeper zk = null; //zookeeper原生api去實現一個分佈式鎖
private String root = "/locks";
private String myZonode; //表示當前獲取到的鎖名稱-也就是節點名稱
private String waitNode; // 表示當前等待的節點
private CountDownLatch latch;
//server鏈接字符串
private static final String CONNECTION_STRING = "139.199.182.26:5000,139.199.182.26:5001,139.199.182.26:5002";
private static final int SESSION_TIMEOUT = 5000; //超時時間
/**
* 構造函數初始化
*
* @param config 表示zookeeper連接串
*/
public DistributeLockDemo(String config) {
try {
zk = new ZooKeeper(config, SESSION_TIMEOUT, this);
Stat stat = zk.exists(root, false); //判斷是不是已經存在locks節點,不需要監聽root節點
if (stat == null) { //如果不存在,則創建根節點
zk.create(root, new byte[0], 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 process(WatchedEvent event) {
System.out.println(event.getPath());
if (this.latch != null) { //如果計數器不爲空話話,釋放計數器鎖
this.latch.countDown();
}
}
/**
* 獲取鎖的方法
*/
public void lock() {
if (tryLock()) {
System.out.println("Thread " + Thread.currentThread().getName() + " - hold lock!");
return;
}
try {
waitLock(waitNode, SESSION_TIMEOUT);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
//等待並獲取鎖
}
/**
* 釋放鎖操作的方法
*/
public void unlock() {
System.out.println("UnLock = " + myZonode);
try {
zk.delete(myZonode, -1);
myZonode = null;
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
}
private boolean tryLock() {
String splitStr = "lock_"; //lock_0000000001
try {
//創建一個有序的臨時節點,賦值給myznode
myZonode = zk.create(root + "/" + splitStr, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(myZonode + " 創建成功");
List<String> subNodes = zk.getChildren(root, false);
Collections.sort(subNodes); //講所有的子節點排序
if (myZonode.equals(root + "/" + subNodes.get(0))) {
//當前客戶端創建的臨時有序節點是locks下節點中的最小的節點,表示當前的客戶端能夠獲取到鎖
return true;
}
//否則的話,監聽比自己小的節點 locks/lock_0000000003
String subMyZnode = myZonode.substring((myZonode.lastIndexOf("/") + 1));
waitNode = subNodes.get(Collections.binarySearch(subNodes, subMyZnode) - 1);// 獲取比當前節點小的節點
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
private boolean waitLock(String lower, long waitTime) throws KeeperException, InterruptedException {
Stat stat = zk.exists(root + "/" + lower, true); //獲取節點狀態,並添加監聽
if (stat != null) {
System.out.println("Thread " + Thread.currentThread().getName() + " waiting for" + root + " /" + lower);
this.latch = new CountDownLatch(1); //實例化計數器,讓當前的線程等待
this.latch.await(waitTime, TimeUnit.MILLISECONDS);
this.latch = null;
}
return true;
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
Semaphore semaphore = new Semaphore(10);
for (int i = 0; i < 10; i++) {
Runnable runnable = () -> { //lambda的一種用法,在java8裏面有。
try {
semaphore.acquire();
DistributeLockDemo distributeLockDemo = new DistributeLockDemo(CONNECTION_STRING);
distributeLockDemo.lock();
//業務代碼
System.out.println(Thread.currentThread().getName() +"開始執行業務代碼");
distributeLockDemo.unlock();
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
executorService.execute(runnable);
}
executorService.shutdown();
}
}