我先简单得介绍一下master-worker设计模式。5个任务每个任务的执行时间是5秒在单线程的情况下需要跑55=25秒,在多线程的情况下 比如说开5个线程则是(5(5+开闭线程的时间))/5 约等于5秒。master-worker就是为了解决这一场景的,当然5个线程必须是逻辑无序的,这点应该容易理解。
Master主人在整个模式中它的作用只有接收和分配任务。
worker 工人则是具体得执行任务。最后将任务返回给master。
相当于将大的任务分成若干小份,并发执行 从而提高效率。
现在我们来设计一下这个系统。
Master
- Master必须要有一个容器来存放任务。这里我们选择ConcurrentLinkedQueue,因为worker肯定是并发的拿到里面的任务去执行。所以我们选择并发类容器来存储任务。
- master可以选用HashMap<String ,Thread>()来存储所有的worker对象。为什么不用concurrentHashMap?因为根本没有涉及到高并发的读写,不过怎么说呢用了也行。
- master需要有容器来存储worker执行完任务后的结果。我就用ConcurrentHashMap<String, Object>(); 来存储。原因同1,因为每个线程执行完任务后肯定是并发地往集合里放数据。
- 因为worek是具体得处理数据。所有必须实现runnable接口,原因不解释。
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class Master {
//任务队列
protected Queue<Object> workQueue= new ConcurrentLinkedQueue<Object>();
//Worker进程队列
protected Map<String ,Thread> threadMap= new HashMap<String ,Thread>();
//子任务处理结果集
protected Map<String ,Object> resultMap= new ConcurrentHashMap<String, Object>();
//是否所有的子任务都结束了
public boolean isComplete(){
for(Map.Entry<String , Thread> entry:threadMap.entrySet()){
if(entry.getValue().getState()!=Thread.State.TERMINATED){
return false;
}
}
return true ;
}
//Master的构造,需要一个Worker进程逻辑,和需要Worker进程数量
public Master(Worker worker,int countWorker){
worker.setWorkQueue(workQueue);
worker.setResultMap(resultMap);
for(int i=0;i<countWorker;i++){
threadMap.put(Integer.toString(i), new Thread(worker, Integer.toString(i)));
}
}
//提交一个任务
public void submit(Object job){
workQueue.add(job);
}
//返回子任务结果集
public Map<String ,Object> getResultMap(){
return resultMap;
}
//开始运行所有的Worker进程,进行处理
public void execute(){
for(Map.Entry<String , Thread> entry:threadMap.entrySet()){
entry.getValue().start();
}
}
}
Worker
- worker要对master的任务队列有引用,毕竟worker是要从master中取任务的
- worker 要对master的结果集合有引用,因为worker执行完结果后要存放结果集合
import java.util.Map;
import java.util.Queue;
public class Worker implements Runnable{
//任务队列,用于取得子任务
protected Queue<Object> workQueue;
//子任务处理结果集
protected Map<String ,Object> resultMap;
public void setWorkQueue(Queue<Object> workQueue){
this.workQueue= workQueue;
}
public void setResultMap(Map<String ,Object> resultMap){
this.resultMap=resultMap;
}
//子任务处理的逻辑,在子类中实现具体逻辑
public Object handle(Object input){
//模拟耗时
Thread.sleep(3000)
return input;
}
@Override
public void run() {
while(true){
//获取子任务
Object input= workQueue.poll();
if(input==null){
break;
}
//处理子任务
Object re = handle(input);
resultMap.put(Integer.toString(input.hashCode()), re);
}
}
}
在worker中我把handle抽了出来。
有了这两个类的话主函数随便写一下。
开5线程5任务多少都行,或者自己把任务抽出来也行。