Barrier接口
public interface Barrier {
String enter() throws InterruptedException, BarrierException;
void leave(String path) throws InterruptedException, BarrierException;
}
单机版的Barrier两个CountDownLatch就可以实现
import java.util.concurrent.CountDownLatch;
/**
* 单机模式的Barrier
*/
public class StandaloneBarrier implements Barrier {
private CountDownLatch startSignal;
private CountDownLatch stopSignal;
public StandaloneBarrier(int count) {
this.startSignal = new CountDownLatch(count);
this.stopSignal = new CountDownLatch(count);
}
@Override
public String enter() throws InterruptedException {
startSignal.countDown();
startSignal.await();
return "success";
}
@Override
public void leave(String path) throws InterruptedException {
stopSignal.countDown();
stopSignal.await();
}
}
分布式版的Barrier,纠正了leave方法里SEQUENTIAL节点删除失败的问题
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.Code;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
/**
* 分布式Barrier
*/
public class DistributedBarrier implements Barrier, Watcher {
private String root;
private String barrierName;
private int count;
private ZooKeeper zooKeeper;
private Lock lock;
private Condition nodeChildrenChange;
private volatile boolean expired;
public DistributedBarrier(String address, String root, String barrierName, int count) throws BarrierException, InterruptedException {
this.root = root;
this.barrierName = barrierName;
this.count = count;
try {
zooKeeper = new ZooKeeper(address, 3000, this);
lock = new ReentrantLock();
nodeChildrenChange = lock.newCondition();
} catch (IOException e) {
throw new BarrierException(e);
}
try {
Stat stat = zooKeeper.exists(root, false);
if (stat == null) {
zooKeeper.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
} catch (KeeperException e) {
if (e.code() != Code.NODEEXISTS) {
throw new BarrierException(e);
}
}
}
@Override
public String enter() throws InterruptedException, BarrierException {
try {
String actualPath = zooKeeper.create(root + "/" + barrierName, new byte[0],
Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
while (!Thread.interrupted() && !expired) {
List<String> list = zooKeeper.getChildren(root, true);
if (list.size() < count) {
lock.lock();
try {
nodeChildrenChange.await();
} finally {
lock.unlock();
}
} else {
return actualPath;
}
}
throw new BarrierException("interruped or expired");
} catch (KeeperException e) {
throw new BarrierException(e);
}
}
@Override
public void leave(String path) throws InterruptedException, BarrierException {
try {
zooKeeper.delete(path, 0);
while (!Thread.interrupted() && !expired) {
List<String> list = zooKeeper.getChildren(root, true);
if (!list.isEmpty()) {
lock.lock();
try {
nodeChildrenChange.await();
} finally {
lock.unlock();
}
}
}
throw new BarrierException("interruped or expired");
} catch (KeeperException e) {
throw new BarrierException(e);
}
}
@Override
public void process(WatchedEvent event) {
if (event.getType() == Watcher.Event.EventType.None) {
if (event.getState() == Watcher.Event.KeeperState.Expired) {
expired = true;
try {
zooKeeper.close();
} catch (InterruptedException e) {
// do nothing;
}
}
} else if (event.getType() == Watcher.Event.EventType.NodeChildrenChanged) {
lock.lock();
try {
nodeChildrenChange.signalAll();
} finally {
lock.unlock();
}
}
}
}