zookeeper分布式锁主要基于临时顺序节点来实现的,为了避免羊群效应。所以要采用队列形式。按照节点大小升序。当节点发现他是最小的节点的时候就持有了锁,处理完之后就释放锁。后续的节点如果发现在他前一个存在节点,就在他之前的上设置监听。当前一个的节点消失的时候就触发监听并持有锁。
以下代码仅为测试用。。。
public class DistributedLock implements Lock {
private ZooKeeper zk = null;
private String basePath = "/lock";
private String node;
private String preNode;
private static Logger logger = Logger.getLogger(DistributedLock.class);
private static int COUNT = 50;
static int ii = 0;
private static CountDownLatch cdl = new CountDownLatch(COUNT);
private CountDownLatch wait = new CountDownLatch(1);
public static void main(String[] args) {
for(int i = COUNT;i>=0;i--){
new Thread(new Runnable() {
public void run() {
System.out.println("开始创建");
DistributedLock lock = new DistributedLock();
cdl.countDown();
// boolean tryLock = lock.tryLock();
lock.lock();
System.out.println("哈哈");
lock.unlock();
}
}).start();;
}
}
public void lock() {
connectionStart();
if(!tryLock()){
try {
System.out.println(ii++);
//监听之前的一个节点
String fullPath = basePath+"/"+preNode;
System.out.println("监听的节点为--"+preNode);
zk.exists(fullPath,true);
wait.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
lock();
}
}
}
public void lockInterruptibly() throws InterruptedException {
}
public boolean tryLock() {
try {
String string = zk.create(basePath+"/", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
node = string.substring(string.length()-10, string.length());
logger.info(node);
return checkMin();
} catch (KeeperException e) {
if(e instanceof ConnectionLossException){
logger.error("再次尝试加锁");
tryLock();
}
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
return false;
}
/**
* 判断是否是最小的节点
* @return
*/
public boolean checkMin(){
try {
List<String> childrens = zk.getChildren(basePath, false);
//如果只有一个节点就是最小的
if(childrens.size() < 2){
logger.info("只有一个节点");
return true;
}
Collections.sort(childrens);//排序
int i = childrens.indexOf(node);//第一次出现的位置
synchronized (this.getClass()) {
if(i<0){
logger.info("本节点丢失");
return false;
}else if(i == 0){
logger.info("本节点是最小的");
return true;
}else{
preNode = childrens.get(i-1);
return false;
}
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
public void unlock() {
connectionStop();
}
public Condition newCondition() {
return null;
}
public void connectionStart(){
try {
zk = new ZooKeeper("39.108.170.73:2181", 6000, new LockWatcher());
cdl.await();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void connectionStop(){
try {
System.out.println("关闭的节点为---"+node);
zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class LockWatcher implements Watcher{
public void process(WatchedEvent event) {
if(event.getType() == EventType.NodeDeleted){
System.out.println("当前的node----"+node+"----删除的node-------"+event.getPath());
logger.info("前一位节点已经消失:"+preNode);
if(checkMin()){
logger.info("加锁成功");
wait.countDown();
}else{
lock();
}
}
}
}
}