多线程设计模式之一——Master-Worker设计模式

1.Master-Worker原理

     1.1) Master-Worker模式是一种常见的并行设计模式之一,并行体现在一下两个方面:

              1.1.1) Client端把待处理的任务交给Master,Master将这个任务拆分成多个子任务交给Worker线程进行处理,

此时Client不需要阻塞的等待Master的处理结果,可以去处理其他的事情

              1.1.2) Master在汇总结果的时候,不用等到Worker把所有的子任务都完成,才一起去汇总处理结果,Master可

以一边先处理Worker已经处理完的子任务,Worker也可以继续处理未完成的子任务

    1.2) Master-Worker工作图

      1.3)Master-Worker模式的结构

             1.3.1)Master-Worker模式是一种使用多线程技术进行数据处理的结果模型

             1.3.2)Master线程为主线程,它维护了一个Worker线程队列,子任务队列和子结果集;Worker线程队列,

不断的从子任务队列中提取任务处理,并把处理结果写入子结果集中去

                                            

2.Master-Worker模式的简单代码实现

   2.1)Master类

package com.roger.multi_thread;

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 {

    //Worker线程队列
    protected Map<String,Thread> workerThreadMap = new HashMap<>();
    //子任务队列,Worker线程队列,不断从子任务队列中,获取待处理的任务进行执行
    protected Queue<Object> subTaskWorkerQueue = new ConcurrentLinkedQueue<>();
    //子任务的结果集存储容器
    protected Map<String,Object> resultMap = new ConcurrentHashMap<>();

    /**
     * 构造Master的时候,需要一个Worker线程逻辑,
     * 以及准备构造几个Worker线程进行子任务的处理
     */
    public Master(Worker worker, int workerCount) {
        worker.setSubTaskWorkerQueue(subTaskWorkerQueue);
        worker.setResultMap(resultMap);

        for(int i = 1; i<= workerCount; i ++){
            workerThreadMap.put(Integer.toString(i),new Thread(worker));
        }
    }

    /**
     * 是否所有的任务都全部执行完成
     * @return
     *      true 所有任务均已结束
     *      false 还有任务待处理中
     */
    public boolean isComplete(){
        for(Map.Entry<String,Thread> threadMap : workerThreadMap.entrySet()){
            if(threadMap.getValue().getState() != Thread.State.TERMINATED){
                return false;
            }
        }
        return true;
    }

    /**
     * 执行Worker子线程
     */
    public void execute(){
        for(Map.Entry<String,Thread> threadMap : workerThreadMap.entrySet()){
            threadMap.getValue().start();
        }
    }

    /**
     * 提交子任务
     * @param task
     */
    public void submit(Object task){
        subTaskWorkerQueue.add(task);
    }

    /**
     * 获取所有子任务的处理结果集
     * @return
     */
    public Map<String, Object> getResultMap() {
        return resultMap;
    }
}

   2.2)Worker线程类的代码

package com.roger.multi_thread;

import java.util.Map;
import java.util.Queue;

public abstract class Worker implements Runnable {
    //Master线程中的所有子任务队列
    public Queue<Object> subTaskWorkerQueue;
    //Master线程中子任务处理的结果集
    public Map<String,Object> resultMap;

    @Override
    public void run() {
        //这里做非空判断的原因是保证代码的高可用
       if(subTaskWorkerQueue == null || subTaskWorkerQueue.isEmpty()){
           return;
       }
       for(;;){
           //使用poll()方法处理,弹出并删除对首的对象
           Object task = subTaskWorkerQueue.poll();
           if(task == null){
               //这个线程处理结束
               break;
           }
           //处理子任务
           Object result = bizProcess(task);
           //这里没有做非空判断的原因,是这里地址传递
           //在构造Master的时候,把Master中的子任务结果集
           //传入Worker子线程中来
           //if(resultMap == null){
               //resultMap = new HashMap<>();
           //}
           //把处理结果存入结果集中去
           resultMap.put(Integer.toString(task.hashCode()),result);
       }
    }

    public void setSubTaskWorkerQueue(Queue<Object> subTaskWorkerQueue) {
        this.subTaskWorkerQueue = subTaskWorkerQueue;
    }

    public void setResultMap(Map<String, Object> resultMap) {
        this.resultMap = resultMap;
    }

    /**
     * 子任务的业务处理结果
     * 具体使用是通过重写bizProcess方法
     * @param task
     * @return
     */
    public abstract Object bizProcess(Object task);
}

     2.3) 具体业务实现类,继承Worker线程类,重写抽象方法 bizProcess(Object task)方法,以计算

                                    1*1*1 + 2*2*2 + 3*3*3 + ... + 100*100+100 = ?

为例。

           2.3.1) 分析这个任务,Master需要把这个任务拆分成100个子任务进行处理,每个任务只需处理1个自然数字的立方即可,

Master负责计算总和

           2.3.2) 子任务的代码实现,继承Worker线程类,重写抽象方法 bizProcess方法

package com.roger.multi_thread;

public class PlusWorker extends Worker {

    @Override
    public Object bizProcess(Object task) {
        Integer num = (Integer) task;
        return num.intValue() * num.intValue()*num.intValue();
    }
}

           2.3.3) 启动类的实现代码

package com.roger.multi_thread;

import java.util.Map;
import java.util.Set;

/**
 * Client向Master递交一个 1到100的立方和相加的任务
 *      1*1*1 + 2*2*2 + 3*3*3 + ... + 100*100*100
 */
public class Bootstrap {

    public static void main(String[] args) {
        PlusWorker plusWorker = new PlusWorker();
        Master master = new Master(plusWorker,5);
        //Master线程拆分子任务,提交到Master管理的子任务队列中去
        for(int i = 1; i <= 100; i ++){
            master.submit(i);
        }

        //Master启动worker子线程,进行子任务的处理,并把子任务处理的结果汇总到
        //Master管理的子任务结果集容器中去
        master.execute();
        //定义一个客户端提交的总任务处理结果的变量
        int result = 0;
        //汇总Master中管理的子任务结果集
        Map<String, Object> resultMap = master.getResultMap();
        //worker线程一边处理子任务,master线程一边汇总结果集
        //结果集中已有Worker线程处理完的子任务结果集
        //或者
        //Master的子任务还没有全部处理完成
        while (!resultMap.isEmpty() || !master.isComplete()){
            //每次只处理一个key的值,循环处理,知道任务结束为止
            Set<String> keySet = resultMap.keySet();
            String key = null;
            for(String k : keySet){
                key = k;
                break;
            }
            int reValue = 0;
            if(key != null){
                reValue = (Integer) resultMap.get(key);
                //移除已经取出的子任务计算结果
                resultMap.remove(key);
            }
            result = result + reValue;
        }

        System.out.println("1*1*1 + 2*2*2 + 3*3*3 + ... + 100*100*100 = " + result);
    }
}

          2.3.4)启动类运行结果:

猜你喜欢

转载自blog.csdn.net/lihongtai/article/details/86001665