1.声明
当前内容主要用于本人学习和复习,当前内容为使用两个标记为当前的所有线程开启一起执行,并实现一起结束
- 使用workersNode作为工作节点的主要节点
- 所有的工作线程直接向workersNode节点下面的注册为子节点,当注册子节点达到执行数量,则开始工作
- 工作线程完毕后直接向finish节点注册节点,表示当前线程工作已经完成
- 通过finish节点的子节点数量达到指定数量则认为所有的节点都完成工作,即任务完成
2.主要实现
1.首先将所有的监听事件抽取出来成为一个抽象类:EventHandler
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
/**
* @description 抽象的监视事件的处理
* @author hy
* @date 2020-06-07
*/
public abstract class EventHandler implements Watcher {
protected String node;
protected ZooKeeper zk;
protected Object mointer;
protected int totalWorker;
public EventHandler(ZooKeeper zk, String node, Object mointer, int totalWorker) {
this.node = node;
this.zk = zk;
this.mointer = mointer;
this.totalWorker = totalWorker;
}
@Override
public void process(WatchedEvent event) {
try {
doProcess(event);
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
abstract void doProcess(WatchedEvent event) throws KeeperException, InterruptedException;
}
2.创建事件FinishWatcher
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooKeeper;
/**
* @description 所有的任务全部完成的监视器
* @author hy
* @date 2020-06-07
*/
public class FinishWatcher extends EventHandler {
public FinishWatcher(ZooKeeper zk, String node, Object mointer, int totalWorker) {
super(zk, node, mointer, totalWorker);
}
@Override
public void doProcess(WatchedEvent event) {
// System.out.println("触发FinishWatcher事件。。。。。。。。。。");
synchronized (mointer) {
try {
List<String> childrenList = zk.getChildren(node, new FinishWatcher(zk, node, mointer, totalWorker));
if (childrenList.size() == totalWorker) {
System.out.println("====所有的节点全部完成任务=====");
mointer.notify();
}
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3.创建事件ReadyWatcher
import java.util.List;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.ZooKeeper;
/**
* @description 工作监视器,用于监视当前的线程是否全部集合完毕
* @author hy
* @date 2020-06-07
*/
public class ReadyWatcher extends EventHandler {
public ReadyWatcher(ZooKeeper zk, String node, Object mointer, int totalWorker) {
super(zk, node, mointer, totalWorker);
}
@Override
public void doProcess(WatchedEvent event) {
synchronized (mointer) {
//System.out.println("触发ReadyWatcher监控事件。。。。。。。。。。");
try {
List<String> childrenList = zk.getChildren(node, new ReadyWatcher(zk, node, mointer, totalWorker));
if (childrenList.size() == totalWorker) {
System.out.println("====所有的节点准备就绪=====");
mointer.notify();
}
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4.创建工作者
import java.io.IOException;
import java.util.List;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
/**
* @description 实际的工作者
* @author hy
* @date 2020-06-07
*/
public class Worker implements Runnable {
private ZooKeeper zk;
private final String workersNode = "/workersNode";// 默认/workerNode
private String finishNode = "/finish";
private Object readyMoniter = new Object();
private Object finishMoniter = new Object();
private String name;
private int totalWorker;
public Worker(String name, int totalWorker) {
this.name = name;
this.totalWorker = totalWorker;
try {
zk = new ZooKeeper("192.168.1.105", 10000, null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void run() {
try {
// 等待所有的线程都集合完毕,然后开始执行任务
readyWait();
doWork();
// 开始完成任务,所有人完成任务后退出
finish();
} catch (KeeperException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 执行之前的所有线程等待操作
public void readyWait() throws KeeperException, InterruptedException {
Stat workeNodeExists = null;
while (true) {
synchronized (readyMoniter) {
Stat stat = zk.exists(workersNode, null);
boolean exists = stat != null;
if (exists) {
workeNodeExists = zk.exists(workersNode + "/" + name, null);
if (workeNodeExists == null) {
// 开始加入当前的节点下面,称为临时节点的序列化的节点
zk.create(workersNode + "/" + name, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,
CreateMode.EPHEMERAL);
workeNodeExists = zk.exists(workersNode + "/" + name, null);
}
// 获取当前执行的总线程数量,即获取当前的节点下面的子节点的数量
List<String> childrenList = zk.getChildren(workersNode,
new ReadyWatcher(zk, workersNode, readyMoniter, totalWorker));
if (childrenList.size() != totalWorker) {
System.out.println(name + ":开始进入等待状态,等待集合");
readyMoniter.wait();
} else {
break;
}
}
}
}
}
// 实际执行任务操作
public synchronized void doWork() throws KeeperException, InterruptedException {
Stat workeNodeExists = zk.exists(workersNode + "/" + name, null);
if (workeNodeExists != null) {
// 开始执行
System.out.println(name + ":开始执行任务");
}
}
// 任务执行完毕后的统一操作
public void finish() throws KeeperException, InterruptedException {
Stat finishNodeExists = zk.exists(finishNode, null);
if(finishNodeExists==null) {
zk.create(finishNode, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
// System.out.println("进入finish模块");
while (true) {
// System.out.println("finish的循环中");
// Thread.sleep(1000L);
synchronized (finishMoniter) {
Stat exists2 = zk.exists(finishNode + "/" + name, false);
// System.out.println("判断节点" + finishNode + "/" + name + "是否存在");
if (exists2 == null) {
// 开始写入当前的finish节点
zk.create(finishNode + "/" + name, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
// System.out.println("判断节点" + finishNode + "/" + name + "已创建");
} else {
System.out.println("所有任务执行完毕。。。");
}
List<String> finishList = zk.getChildren(finishNode,
new FinishWatcher(zk, finishNode, finishMoniter, totalWorker));
// System.out.println("finish的所有子节点" + finishList);
if (finishList.size() == totalWorker) {
// 任务执行完毕
System.out.println("所有的工作者都执行完毕。。。。");
break;
} else {
/* System.out.println(name + ":进入完结等待状态"); */
finishMoniter.wait();
}
}
}
}
}
5.创建测试类
/**
* @description 当前内容用于实现当前Zookeeper上面的Doubble Barriers伪代码
* @author hy
* @date 2020-06-07
*/
public class DoubleBarriersTest {
public static void main(String[] args) throws InterruptedException, IOException {
// int totalWorker = 5;
int totalWorker = 5;
for (int i = 1; i < totalWorker + 1; i++) {
Thread worker = new Thread(new Worker("worker" + i, totalWorker));
Thread.sleep(1000l);
worker.start();
}
/*
* Thread worker1 = new Thread(new Worker("worker1", totalWorker)); Thread
* worker2 = new Thread(new Worker("worker2", totalWorker)); Thread worker3 =
* new Thread(new Worker("worker3", totalWorker)); Thread worker4 = new
* Thread(new Worker("worker4", totalWorker)); Thread worker5 = new Thread(new
* Worker("worker5", totalWorker)); worker1.start(); worker2.start();
* worker3.start(); worker4.start(); worker5.start();
*/
System.in.read();
}
}
3.主要测试
1.首先在zookeeper上面创建节点:/workersNode、/finish
2.启动测试
发现所有的线程都等待到一定的数量时,才开始执行任务,最后获取所有线程任务都完毕的通知
4.分析
- 当前的通过两个节点进行限制方式,大概实现了线程们的工作起点和线程们工作结束的终点
- 发现当前的执行中实际上就是通过当前的zookeeper的节点是否存在来实现的
- 发现的问题就是不能按照顺序进行执行
5.总结
1.本人执行的时候发现了一个问题,那就是在多线程环境下的Watcher需要创建(new),不能使用同一个对象(本人使用同一个对象发现当前的watcher会出现警告)
2.由于不知到什么原因导致线程进行阻塞(wait),并且出现了一直被锁定无法被唤醒的状况(最后发现时Watcher没有new导致的,这说明在多线程环境下,直接使用一个对象好像存在问题,debug发现报错了)
3.再次复习了jps和jstack的使用,使用jstack很容易看到你的线程状态,被什么锁定,处于没有解锁的状态
以上纯属个人见解,如有问题请联本人!