1分布式共享锁的流程图
原理
package cn.itcast.bigdata.zklock;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
public class DistributedClientLock {
// 会话超时
private static final int SESSION_TIMEOUT = 2000;
// zookeeper集群地址
private String hosts = "mini2:2181,mini3:2181,mini4:2181";
// 父节点
private String groupNode = "/locks";
// 子节点
private String subNode = "/locks/sub";
//锁状态标识位
private String haveLock ="/haveLock";
private ZooKeeper zk;
// 记录自己创建的子节点路径
private volatile String thisPath;
/**
* 连接zookeeper
*/
public void connectZookeeper(final String hostName) throws Exception {
zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {
public void process(WatchedEvent event) {
try {
// 判断事件类型,此处只处理子节点变化事件
if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals(groupNode)) {
// 获取子节点,并对父节点进行监听
List<String> childrenNodes = zk.getChildren(groupNode, true);
String thisNode = thisPath.substring((groupNode + "/").length());
// 去比较是否自己是最小id
Collections.sort(childrenNodes);
if (childrenNodes.indexOf(thisNode) == 0) {
// 访问共享资源处理业务,并且在处理完成之后删除锁
doSomething(hostName);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
//
// 判断锁状态标识位节点是否存在,没有就创建
if(zk.exists(haveLock, false)==null) zk.create(haveLock,"0".getBytes(),Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT) ;
// 1、程序一进来就先注册一把锁到zk上
thisPath = zk.create(subNode, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
// 从zk的锁父目录下,获取所有子节点,并且注册对父节点的监听
List<String> childrenNodes = zk.getChildren(groupNode, true);
// 如果争抢资源的程序就只有自己,且锁没有被使用,则可以直接去访问共享资源
byte[] data = zk.getData(haveLock, false, null);
String isHaveLock=new String(data);
//如果只有自己就去获取锁
if (childrenNodes.size() == 1&&isHaveLock.equals("0")) {
doSomething(hostName);
}
}
/**
* 处理业务逻辑,并且在最后释放锁
*/
private void doSomething(String hostName) throws Exception {
try {
System.out.println(hostName+" get lock: " + thisPath);
//修改锁状态标志
zk.setData(haveLock, "1".getBytes(), -1);
// do something
} finally {
System.out.println(hostName+" finished doSomething");
// 释放锁
zk.delete(this.thisPath, -1);
//修改锁状态标志
zk.setData(haveLock, "0".getBytes(), -1);
//并重新注册锁
thisPath = zk.create(subNode, null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println(hostName+" 注册新锁: "+thisPath);
// wait一小会,便于观察
Thread.sleep(new Random().nextInt(3000));
}
}
public static void main(String[] args) throws Exception {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper("hostName");
Thread.sleep(Long.MAX_VALUE);
}
}
测试
public class Test {
public static void main(String[] args) throws Exception {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper("mini2");
Thread.sleep(Long.MAX_VALUE);
}
}
public class Test2 {
public static void main(String[] args) throws Exception {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper("mini3");
Thread.sleep(Long.MAX_VALUE);
}
}public class Test3 {
public static void main(String[] args) throws Exception {
DistributedClientLock dl = new DistributedClientLock();
dl.connectZookeeper("mini4");
Thread.sleep(Long.MAX_VALUE);
}
}