com.zoi7.component.zookeeper.ZkDistributedLock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of component-zookeeper Show documentation
Show all versions of component-zookeeper Show documentation
zookeeper组件, 提供了一个基于zookeeper实现的分布式锁等
package com.zoi7.component.zookeeper;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 yjy
* 2018-10-23 11:15
*/
public class ZkDistributedLock implements Lock, Watcher {
private static final Logger log = LoggerFactory.getLogger(ZkDistributedLock.class);
private static final String ROOT_NAME = "/lockRoot"; // 分布式锁根节点
private static final String FIX = "_seq_";
private ZooKeeper zooKeeper;
private String lockName; // 锁节点
private String waitingLock; // 等待锁
private String currentLock = null; // 当前锁
private CountDownLatch countDownLatch = null;
public ZkDistributedLock(String lockName) throws InterruptedException, IOException, KeeperException {
try {
zooKeeper = ZkUtils.getInstance().getZooKeeper(this);
Stat stat = zooKeeper.exists(ROOT_NAME, false);
if (stat == null) {
zooKeeper.create(ROOT_NAME, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
this.lockName = lockName;
} catch (InterruptedException | KeeperException | IOException e) {
log.error("ZkDistributedLock Instantiation failed", e);
if (zooKeeper != null) {
zooKeeper.close();
}
throw e;
}
}
/**
* 获取锁, 如果当前非空闲, 则等待锁释放
*
* 由于 lock(); 方法如果在遇到阻塞情况将会一直等待下去(等待时间为Long.MAX_VALUE毫秒), 这可能会导致意想不到的情况
* 建议使用 tryLock(time, unit);
*/
@Override
public void lock() {
if (this.tryLock()) {
log.debug("ZkDistributedLock lock > {} success", this.lockName);
return;
}
try {
waitLock(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
/**
* 尝试获取锁, 如果当前非空闲, 则等待, 如果在指定时间内还是未获取到锁, 则获取锁失败
* @param time 时间
* @param unit 时间单位
* @return 是否获取成功
* @throws InterruptedException e
*/
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
if (tryLock()) {
return true;
}
try {
return waitLock(time, unit);
} catch (KeeperException e) {
log.error("tryLock > waitLock error", e);
}
return false;
}
/**
* 尝试获取锁, 直接返回是否成功
* @return 是否成功获取锁
*/
@Override
public boolean tryLock() {
if (lockName.contains(FIX)) {
throw new IllegalArgumentException("wrong lockName: " + lockName + ", can not contains chars : _seq_");
}
try {
// 创建临时节点
String node = ROOT_NAME + "/" + lockName + FIX;
currentLock = zooKeeper.create(node, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
// 查看前方是否有锁
waitingLock = getWaitingLock();
if (waitingLock == null) {
return true;
}
} catch (KeeperException | InterruptedException e) {
log.error("tryLock error", e);
}
return false;
}
/**
* 等待锁释放
* @param waitTime 等待时间
* @param unit 时间单位
* @return 是否成功等到锁释放
* @throws KeeperException e
* @throws InterruptedException e1
*/
private boolean waitLock(long waitTime, TimeUnit unit) throws KeeperException, InterruptedException {
if (waitingLock != null) {
log.info("waitLock > currentLock: {}, waitingLock: {}, waitTime: {}, timeUnit: {}",
currentLock, waitingLock, waitTime, unit);
Stat stat = zooKeeper.exists(ROOT_NAME + "/" + waitingLock, true);
if (stat != null) {
countDownLatch = new CountDownLatch(1);
// if 前方锁释放
if (countDownLatch.await(waitTime, unit)) {
// 还要判断当前前方是否有锁
waitingLock = getWaitingLock();
return waitLock(waitTime, unit);
} else {
return false;
}
}
}
return true;
}
/**
* 找出排在当前锁前方的锁, 如果当前锁已经在最前, 则返回null
* @return 锁名称
* @throws KeeperException
* @throws InterruptedException
*/
private String getWaitingLock() throws KeeperException, InterruptedException {
// 获取根节点的所有子节点
List children = zooKeeper.getChildren(ROOT_NAME, false);
// 找出所有当前锁(lockName)的顺序节点
List curChildren = new ArrayList<>();
for (String child : children) {
if (lockName.equals(child.split(FIX)[0])) {
curChildren.add(child);
}
}
// 排序
Collections.sort(curChildren);
// 找出本次锁所在的位置
int index = curChildren.indexOf(currentLock.substring(ROOT_NAME.length() + 1));
// 如果在第一, 那么获取锁成功
if (index == 0) {
return null;
}
// 否则记录下排在它前面的锁
return curChildren.get(index - 1);
}
@Override
public void lockInterruptibly() {
this.lock();
}
/**
* 释放当前锁
*/
@Override
public void unlock() {
try {
if (currentLock != null) {
zooKeeper.delete(currentLock, -1);
log.info("unlock > currentLock: {}", currentLock);
}
if (zooKeeper != null) {
zooKeeper.close();
}
} catch (InterruptedException | KeeperException e) {
log.error("unlock error, currentLock: " + currentLock, e);
}
}
@Override
public Condition newCondition() {
return null;
}
/**
* 监听锁释放事件
* @param event 事件
*/
@Override
public void process(WatchedEvent event) {
if (event.getType().equals(Event.EventType.NodeDeleted)
&& event.getPath().equals(ROOT_NAME + "/" + waitingLock)) {
if (this.countDownLatch != null) {
this.countDownLatch.countDown();
}
}
}
}