转载:http://blog.csdn.net/qq_15370821/article/details/74011036
使用Curator客户端实现
1.当有客户端访问锁资源时,先在zookeeper服务器上创建的锁节点下创建一个顺序节点,使用完锁资源删除创建的顺序节点。
2.当一个新的客户端想要访问锁资源时,先去zookeeper服务器锁节点下创建一个新节点,判断当前创建的节点编号是否为最小,若为最小表示当前只有本客户端想访问锁资源,然后访问资源便是。
3.若当前创建的节点编号不为最小,表示之前已有客户端在访问锁资源,需排队等待。所以监听比当前节点编号小一号的节点,若前一个节点被删除表示排在当前客户端前面的都执行完了锁资源,可以开始访问锁资源。
客户端操作接口:
public interface DistributedLock {
//获取锁,若没有得到就等待
public void acquire() throws Exception;
//获取锁,直到超时
public boolean acquire(long time,TimeUnit unit) throws Exception;
//释放锁
public void realease() throws Exception;
}
基础类(对zookeeper服务器操作的详细实现):
public class BaseDistributedLock {
private final CuratorFramework client;
private final String path;
protected final String basePath;
private final String lockName;
private final static Integer MAX_RETRY_COUNT = 10;
public BaseDistributedLock(CuratorFramework client, String path, String lockName) {
this.client = client;
this.basePath = path;
this.path = path.concat("/").concat(lockName);
this.lockName = lockName;
}
private void deleteOurpath(String ourPath) throws Exception {
client.delete().guaranteed().deletingChildrenIfNeeded().forPath(ourPath);
}
private String createLockNode(CuratorFramework client, String path) throws Exception {
return client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, null);
}
private boolean waitToLock(long startMillis, Long millisToWait, String ourPath) throws Exception {
boolean haveTheLock = false;
boolean doDelete = false;
try {
while (!haveTheLock){
List<String> children = getSortedChildren();
String sequenceNodeName = ourPath.substring(basePath.length() + 1);
int ourIndex = children.indexOf(sequenceNodeName);
if(ourIndex <0) {
throw new NoNodeException("节点不存在: " + sequenceNodeName);
}
boolean isGetTheLock = ourIndex == 0;
String psthToWatch = isGetTheLock ? null : children.get(ourIndex - 1);
if(isGetTheLock) {
haveTheLock = true;
}else {
String previousSequencePath = basePath.concat("/").concat(psthToWatch);
final CountDownLatch latch = new CountDownLatch(1);
try {
client.getData().usingWatcher(new Watcher() {
@Override
public void process(WatchedEvent event) {
if(event.getType() == EventType.NodeDeleted) {
latch.countDown();
}
}
}
).forPath(previousSequencePath);
if(millisToWait != null) {
millisToWait -= (System.currentTimeMillis() - startMillis);
startMillis = System.currentTimeMillis();
if(millisToWait <= 0) {
doDelete = true;
break;
}
latch.await(millisToWait, TimeUnit.MICROSECONDS);
}else {
latch.await();
}
}catch(NoNodeException e) {
e.printStackTrace();
}
}
}
}catch(Exception e ) {
doDelete = true;
}finally{
if(doDelete) {
deleteOurpath(ourPath);
}
}
return haveTheLock;
}
private String getLockNodeNumber(String str, String lockName ) {
int index = str.lastIndexOf(lockName);
if(index >= 0) {
index += lockName.length();
return index <= str.length() ? str.substring(index) : "";
}
return str;
}
public List<String> getSortedChildren() throws Exception{
try {
List<String> children = client.getChildren().forPath(basePath);
Collections.sort
(
children,
new Comparator<String>()
{
public int compare(String lhs, String rhs)
{
return getLockNodeNumber(lhs, lockName).compareTo(getLockNodeNumber(rhs, lockName));
}
}
);
return children;
}catch(NoNodeException e){
client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(basePath);
return getSortedChildren();
}
}
protected void releaseLock(String lockPath) throws Exception {
deleteOurpath(lockPath);
}
protected String attemptLock(long time, TimeUnit unit) throws Exception {
final long startMillis = System.currentTimeMillis();
final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;
String ourPath = null;
boolean hasTheLock = false;
boolean isDone = false;
int retryCount = 0;
while(!isDone) {
isDone = true;
try{
ourPath = createLockNode(client, path);
hasTheLock = waitToLock(startMillis, millisToWait, ourPath);
}catch(NoNodeException e) {
if(retryCount++ < MAX_RETRY_COUNT) {
isDone = false;
}else {
throw e;
}
}
}
if(hasTheLock) {
return ourPath;
}
return null;
}
}
客户端的具体实现类:
public class SimpleDistributedLock extends BaseDistributedLock implements DistributedLock {
//锁名称前缀
private static final String LOCK_NAME = "lock-";
private String ourLockPath;
public SimpleDistributedLock(CuratorFramework client, String path) {
super(client, path, LOCK_NAME);
}
private boolean internalLock(long time, TimeUnit unit) throws Exception{
ourLockPath = attemptLock(time, unit);
return ourLockPath != null;
}
@Override
public void acquire() throws Exception {
if(!internalLock(-1,null)) {
throw new IOException("连接丢失!" + basePath + "路径不能获取锁");
}
}
@Override
public boolean acquire(long time, TimeUnit unit) throws Exception {
return internalLock(time, unit);
}
@Override
public void realease() throws Exception {
releaseLock(ourLockPath);
}
}
测试类:
public static void main(String[] args) {
RetryPolicy retry = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client1 = CuratorFrameworkFactory.newClient("192.168.0.3:2181", 5000, 5000, retry);
CuratorFramework client2 = CuratorFrameworkFactory.newClient("192.168.0.3:2181", 5000, 5000, retry);
client1.start();
client2.start();
SimpleDistributedLock lock1 = new SimpleDistributedLock(client1, "/Lock");
SimpleDistributedLock lock2 = new SimpleDistributedLock(client1, "/Lock");
try {
lock1.acquire();
System.out.println("Client1 locked");
Thread client2Thr = new Thread(new Runnable() {
@Override
public void run() {
try {
lock2.acquire();
System.out.println("client2 locked");
lock2.realease();
System.out.println("client2 released");
}catch(Exception e) {
e.printStackTrace();
}
}
});
client2Thr.start();
Thread.sleep(5000);
lock1.realease();
System.out.println("client1 released");
client2Thr.join();
}catch(Exception e) {
e.printStackTrace();
}
}
console:
Client1 locked
client1 released
client2 locked
client2 released