Java多线程编程中,常用的多线程设计模式包括:Future模式、Master-Worker模式、Guarded Suspeionsion模式、不变模式和生产者-消费者模式等。这篇文章主要讲述Master-Worker模式,关于其他多线程设计模式的地址如下:
  关于Future模式的详解:并行设计模式(一)-- Future模式
  关于Guarded Suspeionsion模式的详解:并行设计模式(三)-- Guarded Suspeionsion模式
  关于不变模式的详解:并行设计模式(四)-- 不变模式
  关于生产者-消费者模式的详解:并行设计模式(五)-- 生产者-消费者模式

 1. Master-Worker模式

  Master-Worker模式是常用的并行模式之一,它的核心思想是:系统由两类进程协同工作,即Master进程和Worker进程,Master负责接收和分配任务,Wroker负责处理子任务。当各个Worker进程将子任务处理完成后,将结果返回给Master进程,由Master进程进行汇总,从而得到最终的结果,其具体处理过程如下图所示。

  Master-Worker 模式的好处,它能够将一个大任务分解成若干个小任务并行执行,从而提高系统的吞吐量。而对于系统请求者 Client 来说,任务一旦提交,Master进程会分配任务并立即返回,并不会等待系统全部处理完成后再返回,其处理过程是异步的。因此,Client 不会出现等待现象。

2. Master-Worker模式结构

  Master-Worker 模式的结构相对比较简单,Master 进程为主要进程,它维护了一个Worker 进程队列、子任务队列和子结果集、Worker 进程队列中的 Worker 进程,不停地从任务队列中提取要处理的子任务,并将子任务的处理结果写入结果集。具体的结构图如下所示:

注意:Master-Worker 模式是一种使用多线程进行数据处理的结构。多个 Worker 进程协作处理用户请求,Master 进程负责维护 Worker 进程,并整合最终处理结果。

3. 代码实现

  Master-Worker 主要角色分配如下所示:

角 色 作 用

Worker

用于实际处理一个任务

Master

用于任务的分配和最终结果的合成

           Main

启动系统,调用开启Master

下面是一个简易版的 Master-Worker 框架 Java 代码实现

1. Master 部分源码实现:

 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 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 boolean isComplete() {
for(Map.Entry<String, Thread> entry : threadMap.entrySet()) {
if(entry.getValue().getState() != Thread.State.TERMINATED)
return false; //存在未完成的任务
}
return true;
} //提交一个子任务
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();
}
}
}

2. 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){
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);
}
}
}

  以上两段代码已经展示了 Master-Worker 框架的全貌。应用程序中通过重载Worker.handle()方法实现应用层逻辑。

注意:Master-Worker 模式是一种将串行任务并行化的方法,被分解的子任务在系统中可以被并行处理。同时,如果有需要,Master 进程不需要等待所有子任务都完成计算,就可以根据已有的部分结果集计算最终结果。

  现应用这个 Master-Worker 框架,实现一个计算立方和的应用,并计算 1 ~~ 100 的立方和,即 13 + 23  + 33 + ... + 1003

  计算任务可被分解为 100 个子任务,每个子任务仅用于计算单独的立方和。Master 产生固定个数的 Worker 来处理所有这些子任务。Worker 不断地从任务集合中取得这些计算立方和的子任务,并将计算结果返回给 Master。Master 负责将所有 Worker 的任务结果进行累加,从而产生最终的立方和。在整个计算过程中,Master 与 Worker 的运行也是完全异步的,Master 不必等到所有的 Worker 都执行完成后,就可以进行求和操作。即,Master 在获得部分子任务结果集时,就已经可以开始对最终结果进行计算,从而进一步提高系统的并行度和吞吐量。具体的任务分解如下图所示:

  

3.子任务 PlusWork 源码实现

  计算任务被划分成100个子任务,每个任务仅仅用于计算单独的立方和,对应的 PlusWork 源码如下:

public class PlusWorker extends Worker { //求立方和
@Override
public Object handle(Object input) {
int i = (Integer)input;
return i * i * i;
}
}

4. 进行计算的 Main 函数

  运行的调用函数如下。在主函数中首先通过Master类创建5个Worker工作进程和Worker工作实例PlusWorker。在提交了100个子任务后,边开始子任务的计算。这些子任务中由这5个进程共同完成。Master不用等待所有Worker计算完成才开始汇总,而是子任务在计算的过程中,Master就开始汇总了。

 import java.util.Map;
import java.util.Set; public class Application {
public static void main(String[] args) {
//固定使用5个Workde
Master master = new Master(new PlusWorker(), 5);
for(int i=1; i<=100; i++) //提交100个子任务
master.submit(i);
master.execute(); //开始计算
int re = 0; //最终计算结果保存在此
Map<String, Object> resultMap = master.getResultMap(); while(true) {//不需要等待所有Worker都执行完成,即可开始计算最终结果
Set<String> keys = resultMap.keySet(); //开始计算最终结果
String key = null;
for(String k : keys) {
key = k;
break;
}
Integer i = null;
if(key != null)
i = (Integer)resultMap.get(key);
if(i != null)
re += i; //最终结果
if(key != null)
resultMap.remove(key); //移除已被计算过的项目
if(master.isComplete() && resultMap.size()==0)
break;
}
System.out.println(re);
}
}

运行结果:

25502500

 总结:

  重要的事情说三遍,Master-Worker 模式是一种将串行任务并行化的方案,被分解的子任务在系统中可以被并行处理,同时,如果有需要,Master进程不需要等待所有子任务都完成计算,就可以根据已有的部分结果集计算最终结果集。

并行设计模式(二)-- Master-Worker模式的更多相关文章

  1. 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)

    设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...

  2. php设计模式(二):结构模式

    上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式. 一.什么是结构型模式? 结构型模式是解析类和对象的内部结构和外部组 ...

  3. JavaScript设计模式(二):工厂模式

    工厂模式模式的定义与特点 工厂模式(Factory Pattern)是编程中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.在工厂模式中,我们在创建对象时不会对 ...

  4. 【C++设计模式二】工厂模式

    (1)定义3 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂 ...

  5. java设计模式(二)---工厂方法模式

    2普通工厂方法模式 就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建. 2.1创建接口 /** * 发送接口 * Created by mrf on 2016/2/25. */ public ...

  6. 设计模式(二)—工厂方法模式

         凡是出现了大量的实例需要创建,而且具有共同的接口时,可以通过工厂方法模式进行创建. 一个接口: Sender public interface Sender{ public void sen ...

  7. JAVA中的设计模式二(工厂模式)

    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类. 工厂模式主要有: 简单工厂模式,工厂方法,抽象工厂: 简单工厂: 又叫静态工厂,是工厂模式三中状态中结构最为简单的.主 ...

  8. java常用设计模式二:工厂模式

    1.简单工厂模式(静态工厂方法模式) 抽象实例: public interface People { void talk(); } 具体实例: public class Doctor implemen ...

  9. 并行设计模式(一)-- Future模式

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

随机推荐

  1. Chrome等浏览器下出现net::ERR_BLOCKED_BY_CLIENT的解决办法

    当我们在做开发时,调试页面图片会出现部分图片无法正常显示,并且确认图片的地址正确: 按F12 Debug查看报错原因,提示net::ERR_BLOCKED_BY_CLIENT错误,但当我们点击图片地址 ...

  2. Java跨域问题的处理详解

    1,JavaScript由于安全性方面的考虑,不允许页面跨域调用其他页面的对象,那么问题来了,什么是跨域问题? 答:这是由于浏览器同源策略的限制,现在所有支持JavaScript的浏览器都使用了这个策 ...

  3. 学习SVG 重点汇总

    什么是SVG? Δ  SVG 指可伸缩矢量图形 (Scalable Vector Graphics) Δ  SVG 用来定义用于网络的基于矢量的图形 Δ  SVG使用XML格式来定义图形 Δ  SVG ...

  4. Unix英雄传:图文细数十五位计算机先驱

    Unix,一款多任务多用户操作系统,最早由AT&T公司员工及合作伙伴在贝尔实验室于1969年开发完成.Unix的衍生及克隆版本包括Berkeley Unix.Minix.Linux.AIX.A ...

  5. [Java第一课]环境变量的配置以及eclipse一些常用快捷键

    1.环境变量的配置(这里对xp系统电脑来说:) 首先安装jdk软件. 然后在我的电脑(右键)-->属性-->高级-->环境变量-->系统变量(注意)-->新建(新建两个p ...

  6. 数据帧CRC32校验算法实现

    本文设计思想采用明德扬至简设计法.由于本人项目需要进行光纤数据传输,为了保证通信质量要对数据进行校验.在校验算法中,最简单最成熟的非CRC校验莫属了. 得出一个数的CRC校验码还是比较简单的: 选定一 ...

  7. HandlerThread学习

    之前基本讲过Handler的一些知识了,我们今天学习下Google封装的一个实现线程通信的一个类HandlerThread 一.HandlerThread使用 @Override protected ...

  8. bug:翻页

    本章主要分享下,个人测试经历中遇见过的翻页bug 一.列表翻页 1.bug1:去请求翻页page=0,从0页开始算.一般来说page=0 和 page=1的数据是一模一样,所以翻第2页时会发现和第1页 ...

  9. 如何清楚微信页面的缓存(静态资源(图片,js,页面))

    就不说啥子原因了,反正就是微信的缓存问题,照着下面的做法做,一定ok了. 不过就是有些麻烦,但是微信的缓存是为了提高自身的性能,我们这些开发要用人家的平台,只有自己去填坑了. 直接贴代码好了,加上去就 ...

  10. HDU 4267 A Simple Problem with Integers(树状数组区间更新)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K ...