Zookeeper:实现节点Double Barriers(即两次限定操作)

1.声明

当前内容主要用于本人学习和复习,当前内容为使用两个标记为当前的所有线程开启一起执行,并实现一起结束

  1. 使用workersNode作为工作节点的主要节点
  2. 所有的工作线程直接向workersNode节点下面的注册为子节点,当注册子节点达到执行数量,则开始工作
  3. 工作线程完毕后直接向finish节点注册节点,表示当前线程工作已经完成
  4. 通过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.分析

  1. 当前的通过两个节点进行限制方式,大概实现了线程们的工作起点和线程们工作结束的终点
  2. 发现当前的执行中实际上就是通过当前的zookeeper的节点是否存在来实现的
  3. 发现的问题就是不能按照顺序进行执行

5.总结

1.本人执行的时候发现了一个问题,那就是在多线程环境下的Watcher需要创建(new),不能使用同一个对象(本人使用同一个对象发现当前的watcher会出现警告)

2.由于不知到什么原因导致线程进行阻塞(wait),并且出现了一直被锁定无法被唤醒的状况(最后发现时Watcher没有new导致的,这说明在多线程环境下,直接使用一个对象好像存在问题,debug发现报错了)

3.再次复习了jps和jstack的使用,使用jstack很容易看到你的线程状态,被什么锁定,处于没有解锁的状态

以上纯属个人见解,如有问题请联本人!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值