zookeeper实现的分布式锁
代码例子:
package com;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 基于zookeeper的分布式锁
* @author zzp
*/
@Slf4j
public class ZookeeperDistributedLock implements Lock, Watcher {
/**
* ZooKeeper
*/
private ZooKeeper zookeeper = null;
/**
* 根节点
*/
private static final String ROOT_LOCK = "/locks";
/**
* 竞争的资源
*/
private String lockName;
/**
* 等待的前一个锁
*/
private String WAIT_LOCK;
/**
* 当前锁
*/
private String CURRENT_LOCK;
/**
* 计数器
*/
private CountDownLatch countDownLatch;
/**
* 连接zookeeper超时时间
*/
private static final int SESSION_TIME_OUT = 30000;
/**
*
*/
private List<Exception> exceptionList = new ArrayList<>();
public ZookeeperDistributedLock() {
}
/**
* 构建ZookeeperDistributedLock
* @param zookeeperAddress
* @param lockName
*/
public ZookeeperDistributedLock(String zookeeperAddress, String lockName) {
this.lockName = lockName;
try {
zookeeper = new ZooKeeper(zookeeperAddress, SESSION_TIME_OUT, this);
Stat stat = zookeeper.exists(ROOT_LOCK, false);
if (stat == null) {
zookeeper.create(ROOT_LOCK, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
} catch (IOException e) {
log.error("连接zookeeper:" + zookeeperAddress +"失败:" + e.getMessage(), e);
} catch (InterruptedException e) {
log.error("zookeeper exists:" + zookeeperAddress + "中断:" + e.getMessage(), e);
} catch (KeeperException e) {
log.error("zookeeper KeeperException:" + zookeeperAddress +":" + e.getMessage(), e);
}
}
@Override
public void lock() {
try {
if (exceptionList.size() > 0) {
throw new Exception(exceptionList.get(0));
}
if (this.tryLock()) {
System.out.println(Thread.currentThread().getName() + " " + lockName + "获得了锁");
return;
} else {
// 等待锁
waitForLock(WAIT_LOCK, SESSION_TIME_OUT);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void lockInterruptibly() {
this.lock();
}
@Override
public boolean tryLock() {
try {
String lockSuffix = "_lock_";
if (lockName.contains(lockSuffix)) {
throw new Exception("锁名有误,不规范");
}
CURRENT_LOCK = zookeeper.create(ROOT_LOCK + lockName + lockSuffix, new byte[0],
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
List<String> subNodes = zookeeper.getChildren(ROOT_LOCK, false);
// 取出所有lockName的锁
List<String> lockNames = new ArrayList<>();
if (CollectionUtils.isNotEmpty(subNodes)) {
for (String subNode : subNodes) {
String _lockName = subNode.split(lockSuffix)[0];
if (_lockName.equals(lockName)) {
lockNames.add(subNode);
}
}
Collections.sort(lockNames);
// 若当前节点为最小节点,则获取锁成功
if (CURRENT_LOCK.equals(ROOT_LOCK + "/" + lockNames.get(0))) {
return true;
}
// 若不是最小节点,则找到自己的前一个节点
String prevNode = CURRENT_LOCK.substring(CURRENT_LOCK.lastIndexOf("/") + 1);
WAIT_LOCK = lockNames.get(Collections.binarySearch(lockNames, prevNode) - 1);
}
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 等待锁
* @param prev
* @param waitTime
* @return
* @throws KeeperException
* @throws InterruptedException
*/
private boolean waitForLock(String prev, long waitTime) throws KeeperException, InterruptedException {
Stat stat = zookeeper.exists(ROOT_LOCK + "/" + prev, true);
if (stat != null) {
System.out.println(Thread.currentThread().getName() + "等待锁 " + ROOT_LOCK + "/" + prev);
this.countDownLatch = new CountDownLatch(1);
// 计数等待,若等到前一个节点消失,则precess中进行countDown,停止等待,获取锁
this.countDownLatch.await(waitTime, TimeUnit.MILLISECONDS);
this.countDownLatch = null;
System.out.println(Thread.currentThread().getName() + " 等到了锁");
}
return true;
}
@Override
public boolean tryLock(long time, TimeUnit unit) {
try {
if (this.tryLock()) {
return true;
}
return waitForLock(WAIT_LOCK, time);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public void unlock() {
try {
log.info("释放锁 " + CURRENT_LOCK);
zookeeper.delete(CURRENT_LOCK, -1);
CURRENT_LOCK = null;
zookeeper.close();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
}
@Override
public Condition newCondition() {
return null;
}
@Override
public void process(WatchedEvent watchedEvent) {
if (countDownLatch != null) {
countDownLatch.countDown();
}
}
}