Master-Worker并发组件设计模拟
Master-Worker模式是常用的并行计算模式。它的核心思想是系统由两类进程协作工作:
Master进程和Worker进程。
Master负责接收和分配任务,Worker负责处理子任务。当各个Worker子进程处理完成后,
会将结果返回给Master,由Master做归纳和总结。
其好处是能将一个大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量。
代码结构;
代码实现:
执行的任务
package com.bfxy.thread.core.design.masterworker;
public class Task {
private int id;
private int count;
public Task() {
}
public Task(int id, int count) {
this.id = id;
this.count = count;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
master:
//1 承装任务的一个容器:支持高并发无界队列
private ConcurrentLinkedQueue<Task> taskQueue = new ConcurrentLinkedQueue<>();
//2 承装worker执行器:只需要执行数据不需要收集所以用HashMap
private HashMap<String, Thread> workers = new HashMap<>();
//3 接受worker处理成功的结果集合:高并发中存放结果集合所以使用ConcurrentHashMap
private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<>();
package com.bfxy.thread.core.design.masterworker;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Master {
//1 承装任务的一个容器:
private ConcurrentLinkedQueue<Task> taskQueue = new ConcurrentLinkedQueue<>();
//2 承装worker执行器
private HashMap<String, Thread> workers = new HashMap<>();
//3 接受worker处理成功的结果集合
private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<>();
//4 构造方法里面,要对worker进行一个初始化操作
public Master(Worker worker, int workCount) {
//4.1 每一个worker 应该有master里 任务队列容器的引用
worker.setTaskQueue(this.taskQueue);
//4.2 每一个worker 应该有master里 结果集容器的引用
worker.setResultMap(this.resultMap);
//4.3 我们把所有的worker进行初始化 放入 workers容器中
for(int i = 0; i < workCount; i ++){
this.workers.put(Integer.toString(i), new Thread(worker));
}
}
//5 需要一个提交任务的方法
public void submit(Task task) {
this.taskQueue.add(task);
}
//6 需要有一个真正让我们Master里的所有Worker进行工作的方法
public void execute() {
for(Map.Entry<String, Thread> me : this.workers.entrySet()) {
me.getValue().start();
}
}
//7 需要有一个统计的方法,用于合并结果集
public int getResult() {
int sum = 0;
for(Map.Entry<String, Object> me : resultMap.entrySet()) {
sum += (Integer)me.getValue();
}
return sum;
}
//8 判断是否所有的worker都完成工作了 如果完成返回true
public boolean isComplete() {
for(Map.Entry<String, Thread> me : this.workers.entrySet()) {
if(me.getValue().getState() != Thread.State.TERMINATED){
return false;
}
}
return true;
}
}
worker:属于线程执行类需要继承runnable接口
this.taskQueue.poll();//poll()方法,取到元素移除
package com.bfxy.thread.core.design.masterworker;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Worker implements Runnable {
private ConcurrentLinkedQueue<Task> taskQueue;
private ConcurrentHashMap<String, Object> resultMap;
public void setTaskQueue(ConcurrentLinkedQueue<Task> taskQueue) {
this.taskQueue = taskQueue;
}
public void setResultMap(ConcurrentHashMap<String, Object> resultMap) {
this.resultMap = resultMap;
}
@Override
public void run() {
while(true) {
Task task = this.taskQueue.poll();
if(task == null) break;
try {
Object result = handle(task);
this.resultMap.put(Integer.toString(task.getId()), result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private Random r = new Random();
//实际做每一个工作!
private Object handle(Task task) throws Exception {
//每一个任务处理的时间是:
//Thread.sleep(200 * r.nextInt(10));
Thread.sleep(200);
int ret = task.getCount();
return ret;
}
}
主函数测试:
package com.bfxy.thread.core.design.masterworker;
import java.util.Random;
public class Main {
public static void main(String[] args) {
System.err.println("线程数:" + Runtime.getRuntime().availableProcessors());
Master master = new Master(new Worker(), Runtime.getRuntime().availableProcessors());
Random r = new Random();
for(int i = 0; i < 100; i ++) {
Task t = new Task(i, r.nextInt(1000));
master.submit(t);
}
master.execute();
long start = System.currentTimeMillis();
//CountDownLatch
while(true) {
if(master.isComplete()) {
long end = System.currentTimeMillis();
int result = master.getResult();
System.err.println("最终执行结果: " + result + ", 总耗时: " + (end - start));
break;
}
}
}
}