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很容易看到你的線程狀態,被什麼鎖定,處於沒有解鎖的狀態
以上純屬個人見解,如有問題請聯本人!