1.实现pom文件的导入
2.设置好日志输出的配置
以上为基础配置,当然你的虚拟机要有配置的docker容器zookeeper。
主要思想:
a、在获取分布式锁的时候在locker节点下创建节点,释放锁的时候释放该节点。
b、客户端调用createNode方法在path下创建临时顺序节点,然后获取该子节点,注意此时不用设置任何Watcher。
c、客户端获取到所有的节点path之后,那么就认为该客户端获取到了锁。
d、如果发现自己创建的节点已经占用,说明自己还没有获取到锁,此时客户然后对其调用exist()方法,同时对其注册事件监听器,客户端等待。
e、之后,让这个被关注的节点删除,则客户端的Watcher会收到相应通知,如果不是则重复以上步骤继续获取到比自己小的一个节点并注册监听。
当然我们要用到模板设计模式,在阎宏博士的《JAVA与模式》一书中开头是这样描述模板方法(Template Method)模式的:
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
首先定义加锁和释放锁的接口中方法
public interface Zklock {
public void zkLock();
public void zkUnLock();
}
然后做一个抽象模板类,里面配置好zookeeper信息和路径,子类也可以使用
public abstract class ZookperAbstractLock implements Zklock {
public static final String ZKSERVER="192.168.111.111:2181";
public static final int TimeOut=45*1000;
protected String path="/zklock0401";
//这是countdown锁,实现类将会体现他的价值
protected CountDownLatch countDownLatch=null;
ZkClient zkClient=new ZkClient(ZKSERVER,TimeOut);
@Override
public void zkLock() {
if(tryZklock()){
System.out.println(Thread.currentThread().getName()+"占用锁成功");
}else{
waitZkLock();
zkLock();
}
}
protected abstract void waitZkLock();
public abstract boolean tryZklock();
@Override
public void zkUnLock() {
if(zkClient !=null){
zkClient.close();
}
System.out.println(Thread.currentThread().getName()+"\t释放锁成功");
System.out.println();
System.out.println();
}
}
下面就是具体代码正在实现
1首先是实现上锁的方法,这个容易实现,在该路径下建立节点就可以
public boolean tryZklock() {
try {
zkClient.createEphemeral(path);
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
2.其他服务进来就要等待实现
a:要实现对该节点的监听,我们监听的是删除事件
b:当存在该路径,调用exists方法,我们就要等待,不能往下走,于是就用到了 contdownlunch
c:当监听到删除事件时,countDownLatch.countDown()。抢到监听器之后用完就释放
public void waitZkLock() {
IZkDataListener iZkDataListener=new IZkDataListener() {
@Override
public void handleDataChange(String s, Object o) throws Exception {
}
@Override
public void handleDataDeleted(String s) throws Exception {
if(countDownLatch!=null){
countDownLatch.countDown();
}
}
};
zkClient.subscribeDataChanges(path,iZkDataListener);
if(zkClient.exists(path)) {
//等着不能往下走
countDownLatch = new CountDownLatch(1);
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//抢到监听器之后用完就释放
zkClient.unsubscribeDataChanges(path,iZkDataListener);
}