分布式鎖有多重實(shí)現(xiàn)方式,比如數(shù)據(jù)庫 、 redis都可以實(shí)現(xiàn)莲镣。作為分布式協(xié)同工具zookeeper也可以實(shí)現(xiàn)分布式鎖曙强。
1残拐、實(shí)現(xiàn)思路
- 每個(gè)客戶端往/Locks下創(chuàng)建臨時(shí)有序節(jié)點(diǎn),/Locks/Lock_ 創(chuàng)建成功后/Locks下面會(huì)有每個(gè)客戶端對(duì)應(yīng)的節(jié)點(diǎn)碟嘴,比如 /Locks/Lock_000001
- 客戶端取得/Locks下的子節(jié)點(diǎn)溪食,并進(jìn)行排序,判斷在最前面的是否為自己娜扇,如果自己的鎖節(jié)點(diǎn)在第一位错沃,代表獲得鎖成功。
- 如果自己的鎖節(jié)點(diǎn)不再第一位雀瓢,則監(jiān)聽自己前一位的鎖節(jié)點(diǎn)枢析。例如, 自己鎖節(jié)點(diǎn)/Lock_000002刃麸,那么則監(jiān)聽Lock_000001
- 當(dāng)前一位鎖節(jié)點(diǎn)(Lock_000001)對(duì)應(yīng)的客戶端執(zhí)行完成醒叁,釋放鎖,將會(huì)觸發(fā)監(jiān)聽客戶端(Lock_0000002) 的邏輯
- 監(jiān)聽客戶端重新執(zhí)行第2步邏輯泊业,判斷自己是否獲得了鎖
監(jiān)聽機(jī)制把沼,臨時(shí)有序節(jié)點(diǎn)
public class Mylock{
//zk的連接串
String IP = "127.0.0.1:2181";
//計(jì)數(shù)器對(duì)象
CountDownLatch countDownLatch = new CountDownLatch(1);
//zk配置信息
Zookeeper zooKeeper;
private static final String LOCK_ROOT_PATH = "/Locks";
private static final String LOCK_NODE_PATH = "Lock_";
private String lockPath;
//打開zookeeper的鏈接
public MyLock(){
try{
zooKeeper = new ZooKeeper(IP,5000,new watcher(){
@Override
public void process(WatchedEvent event){
if(event.getType==Event.EventType.None){
if(event.getState()==Event.KeeperState.SyncConnected){
System.out.println("連接創(chuàng)建成功~~~");
countDownLatch.countDown();
}
}
}
});
countDownLatch.await();
}catch(Exception e){
e.printStackTrace();
}
}
public void acquireLock() throws Exception{
//創(chuàng)建鎖節(jié)點(diǎn)
createLock();
//嘗試獲取鎖
attempLock();
}
//創(chuàng)建鎖節(jié)點(diǎn)
public void createLock() throws Exception{
//1、打開zookeeper連接
//2吁伺、創(chuàng)建Locks根節(jié)點(diǎn)(創(chuàng)建前先用exit判斷是否存在饮睬,不存在創(chuàng)建)
Stat stat = zooKeeper.exists(LOCK_ROOT_PATH,false);
if(stat == null){
zooKeeper.create(LOCK_ROOT_PATH,new byte[0],ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
}
// 3、創(chuàng)建臨時(shí)有序節(jié)點(diǎn)
lockPath = zooKeeper.create(LOCK_ROOT_PATH + "/" +LOCK_NODE_PATH,new byte[0] ,
ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("創(chuàng)建節(jié)點(diǎn)成功~~~" + lockPath);
//進(jìn)行測(cè)試一下~~箱蝠,看看我們的代碼是否有問題~~
}
}
- 嘗試獲取鎖
//監(jiān)視器對(duì)象续捂,監(jiān)視上一個(gè)節(jié)點(diǎn)是否被刪除\
Watcher watcher = new Watcher(){
@Override
public void proccess(WatcherEvent event){
if(event.getType()==EventType.NodeDeleted){
sychronized(this){
notifyAll();
}
}
}
}
private void attempLock() throws Exception{
//1垦垂、獲取locks下的所有子節(jié)點(diǎn)
List<String> list = zookeeper.getChildren(LOCK_ROOT_PATH,false);
//2、對(duì)子節(jié)點(diǎn)進(jìn)行排序
Collections.sort(list);
//3牙瓢、截取掉前面部分
int index = list.indexOf(lockPath.substring(LOCK_ROOT_PATH.length()+1));
//4劫拗、對(duì)索引進(jìn)行判斷
if(index == 0) {
System.out.ptintln("說明是第1位,獲取鎖成功矾克!")
return;
}eles{
//獲取上一個(gè)節(jié)點(diǎn)的路徑
String path = list.get(index-1);
//監(jiān)視上一個(gè)節(jié)點(diǎn)
Stat stat = zookeeper.exists(LOCk_ROOT_PATH+"/"+path,watcher); //監(jiān)視器對(duì)象页慷,監(jiān)視上一個(gè)節(jié)點(diǎn)是否被刪除
if(stat==null){
//回調(diào),嘗試重新獲得鎖
attempLock();
}else{
//阻塞等待
synchronized(watcher){
watcher.wait();
}
attempLock();
}
}
}
- 釋放鎖
public void releaseLock() throws Exception{
//刪除臨時(shí)有序節(jié)點(diǎn)
zooKeeper.delete(this.lockPath,-1);
zooKeeper.close();
System.out.println("鎖已經(jīng)釋放了~~~);
}