最近在弄分布式
用到的是Zookeeper还只是初步用到了一下同步锁没做进一步的应用
想了解Zookeeper 大家都推荐:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/这个文章 是不错
直接贴代码:
package com.zookeeper.test;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
public class ZkDistributedLock implements Watcher {
private ZooKeeper zk;
private String config = "192.168.1.213:2181";
private String root = "/locks"; // 锁的根节点
private String lockName; // 竞争节点前缀
private String waitNode; // 被监听的前一个节点
private String newNode; // 当前节点
private CountDownLatch latch; // 计数器
private int sessionTimeout = 60 * 1000; // zookeeper会话超时时间
/**
* 创建Zookeeper连接并建立跟目录
*/
public ZkDistributedLock(String lockName) {
this.lockName = lockName;
try {
zk = new ZooKeeper(config, sessionTimeout, this);
Stat stat = zk.exists(root, false);
if (stat == null) {
// 创建根节点
zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.PERSISTENT);
}
} catch (IOException e) {
System.out.println("ZkDistributedLock对象初始化失败,IOException:" + e);
} catch (KeeperException e) {
System.out.println("ZkDistributedLock对象初始化失败,KeeperException:" + e);
} catch (InterruptedException e) {
System.out.println("ZkDistributedLock对象初始化失败,InterruptedException:"
+ e);
}
}
/**
* 监听器动作
*/
public void process(WatchedEvent event) {
if (this.latch != null) {
System.out.println("process监听被触发:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())+Thread.currentThread().getId());
this.latch.countDown();
}
}
/**
* 上锁操作
*
* @return
*/
public boolean lock() {
if (tryLock()) {
return true;
} else {
return waitForLock(waitNode, sessionTimeout);
}
}
/**
* 尝试获取锁操作
*
* @return
*/
private boolean tryLock() {
String splitStr = "_lock_";
try {
// 创建临时子节点
newNode = zk.create(root + "/" + lockName + splitStr, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("子节点:" + newNode + "成功建立!");
// 取出所有子节点
List<String> subNodes = zk.getChildren(root, false);
// 取出所有lockName的锁
List<String> lockObjNodes = new ArrayList<String>();
for (String node : subNodes) {
String _node = node.split(splitStr)[0];
if (_node.equals(lockName)) {
lockObjNodes.add(node);
}
}
Collections.sort(lockObjNodes);
if (newNode.equals(root + "/" + lockObjNodes.get(0))) {
// 如果是最小的节点,则表示取得锁
System.out.println("Thread" + Thread.currentThread().getId()
+ newNode + " get lock !");
return true;
}
// 如果不是最小的节点,找到比自己小1的节点
String subNewNode = newNode.substring(newNode.lastIndexOf("/") + 1);
waitNode = lockObjNodes.get(Collections.binarySearch(lockObjNodes,
subNewNode) - 1);
} catch (KeeperException e) {
System.out.println("尝试获取锁操作失败,KeeperException:" + e);
} catch (InterruptedException e) {
System.out.println("尝试获取锁操作失败,InterruptedException:" + e);
}
return false;
}
/**
* 等待前一个节点开锁
*
* @param lower
* @param waitTime
* @return
*/
private boolean waitForLock(String lower, long waitTime) {
Stat stat;
try {
stat = zk.exists(root + "/" + lower, true);
// 判断比自己小一个数的节点是否存在,如果不存在则无需等待锁,同时注册监听
if (stat != null) {
System.out.println("Thread " + Thread.currentThread().getId()
+ " waiting for " + root + "/" + lower);
this.latch = new CountDownLatch(1);
this.latch.await(waitTime, TimeUnit.MILLISECONDS);
System.out.println(newNode+"节点获得锁!");
this.latch = null;
}
return true;
} catch (KeeperException e) {
System.out.println("等待前一个节点开锁失败,KeeperException:" + e);
} catch (InterruptedException e) {
System.out.println("等待前一个节点开锁失败,InterruptedException:" + e);
}
return false;
}
/**
* 解锁
*/
public void unlock() {
try {
System.out.println("子节点:" + newNode + "已解锁!");
zk.delete(newNode, -1);
newNode = null;
zk.close();
} catch (InterruptedException e) {
System.out.println("解锁异常,InterruptedException:" + e);
} catch (KeeperException e) {
System.out.println("解锁异常,KeeperException:" + e);
}
}
}
还只是初步运用 有什么问题 欢迎指正
感觉要注意的是 会话超时 下一个锁就会自动启动 因为这情况 我在测试的时候还以为代码bug
然后还一个创建zk连接的时候
就算服务器关闭也不会报错
所以我推测创建zk连接其实只是保存了连接信息没实际访问服务器
要到访问文件目录的时候才实际连服务器
我没时间看源码
不知道这个推测是不是正确