美文网首页
Java并发案例05---Master-Worker模式

Java并发案例05---Master-Worker模式

作者: 枫叶_huazhe | 来源:发表于2017-11-07 17:36 被阅读0次

Master-Worker 模式是常用的并行计算模式。它的核心思想是系统由两类进程协同工作,Master和Worker进程。Master负责接收和分配任务,Worker负责处理子任务。当各个Worker子进程处理完毕后,会将结果返回给Master,由Master做归纳和小结。其好处是能够将一个大任务分解成若干个小任务,并行执行,从而提高系统的吞吐量。

Master-Worker模式结构图

结构图1 结构图2

代码架构:

image
Master 负责接收和分配任务
Worker 负责处理子任务
Main 主函数,启动类

Master类

public class Master {

    //1 有一个盛放任务的容器  1.任务不需要阻塞   2.性能高   3.线程安全,每一个worker来这里拿100个task,所以要考虑线程安全。
    private ConcurrentLinkedQueue<Task> workQueue = new ConcurrentLinkedQueue<Task>();
    
    //2 需要有一个盛放worker的集合    1.不存在多线程争抢场景
    private HashMap<String, Thread> workers = new HashMap<String, Thread>();
    
    //3 需要有一个盛放每一个worker执行任务的结果集合   结果集,多个worker并发回写操作
    private ConcurrentHashMap<String, Object> resultMap = new ConcurrentHashMap<String, Object>();
    
    //4 构造方法
    public Master(Worker worker , int workerCount){
        worker.setWorkQueue(this.workQueue);
        worker.setResultMap(this.resultMap);
        
        for(int i = 0; i < workerCount; i ++){
            this.workers.put(Integer.toString(i), new Thread(worker));
        }
        
    }
    
    //5 需要一个提交任务的方法
    public void submit(Task task){
        this.workQueue.add(task);
    }
    
    //6 需要有一个执行的方法,启动所有的worker方法去执行任务
    public void execute(){
        for(Map.Entry<String, Thread> me : workers.entrySet()){
            me.getValue().start();
        }
    }

    //7 判断是否运行结束的方法
    public boolean isComplete() {
        for(Map.Entry<String, Thread> me : workers.entrySet()){
            if(me.getValue().getState() != Thread.State.TERMINATED){
                return false;
            }
        }       
        return true;
    }

    //8 计算结果方法
    public int getResult() {
        int priceResult = 0;
        for(Map.Entry<String, Object> me : resultMap.entrySet()){
            priceResult += (Integer)me.getValue();
        }
        return priceResult;
    }
    
}

需要说明的几点:
1.存放任务的容器,需要一个高并发,线程安全,性能好的容器,因为每一个Worker都回来这里取任务执行,存在线程安全问题,因此选择ConcurrentLinkedQueue。
2.存放结果的容器,同样,worker也持有他的引用,每一个worker做完事情后,会把结果写入这个map中,存在线程安全问题,所以采用ConcurrentHashMap。
3.存放worker的容器没有线程并发访问,只在Master类中进行了遍历,不存在线程安全问题。

Worker类

public class Worker implements Runnable {

    private ConcurrentLinkedQueue<Task> workQueue;
    private ConcurrentHashMap<String, Object> resultMap;
    
    public void setWorkQueue(ConcurrentLinkedQueue<Task> workQueue) {
        this.workQueue = workQueue;
    }

    public void setResultMap(ConcurrentHashMap<String, Object> resultMap) {
        this.resultMap = resultMap;
    }
    
    @Override
    public void run() {
        while(true){
            Task input = this.workQueue.poll();
            if(input == null) break;
            Object output = handle(input);
            System.out.println("当前线程"+Thread.currentThread().getName()+"  计算完毕"+ input);
            this.resultMap.put(Integer.toString(input.getId()), output);
        }
    }

    private Object handle(Task input) {
        Object output = null;
        try {
            //处理任务的耗时。。 比如说进行操作数据库。。。
            Thread.sleep(500);
            output = input.getPrice();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return output;
    }

}

Worker类需要实现Runnable接口

任务类

public class Task {

    private int id;
    private int price ;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Task [id=" + id + ", price=" + price + "]";
    } 
    
}

任务类比较简单,不再敖述。

接下来是启动类

public class Main {

    public static void main(String[] args) {
        /**20个worker*/
        Master master = new Master(new Worker(), 20);
        
        Random r = new Random();
        //100 个任务
        for(int i = 1; i <= 1000; i++){
            Task t = new Task();
            t.setId(i);
            t.setPrice(r.nextInt(1000));
            //添加任务
            master.submit(t);
        }
        //执行任务
        master.execute();
        long start = System.currentTimeMillis();
        
        while(true){
            if(master.isComplete()){
                long end = System.currentTimeMillis() - start;
                int priceResult = master.getResult();
                System.out.println("最终结果:" + priceResult + ", 执行时间:" + end);
                break;
            }
        }
        
    }
}

运行结果如下

image

总结

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

相关文章

  • Java并发案例05---Master-Worker模式

    Master-Worker 模式是常用的并行计算模式。它的核心思想是系统由两类进程协同工作,Master和Work...

  • JAVA Balking 模式(犹豫模式)

    原文案例来自于《java 高并发编程详解》 Balking 模式释义 比如我们在用word 编写文档的时候,每次文...

  • java学习记录--ThreadLocal使用案例

    java学习记录--ThreadLocal使用案例 标签(空格分隔): java 本文借由并发环境下使用线程不安全...

  • Phaser的使用介绍

    本案例参考至《Java7并发编程实战手册》 在java并发编程的过程中,往往会遇到这样的需求:现在有多个工人,每个...

  • Java并发教程

    Java并发教程 Java并发概述Java并发环境设置Java并发主要操作Java并发性线程间通信Java并发同步...

  • Master-Worker工具使用文档

    本案例测试Master-Worker并发设计模式,网上关于该模式,都大差不差,本案例使用线程池的方式,重新实现,并...

  • Singleton模式(设计模式)

    Main.java Singleton.java 多线程不安全模式下的Singleton模式案例: Main.ja...

  • 并行模式与算法

    java高并发程序设计 - 网易云课堂 一、单例模式 高并发情况下的单例模式 public class Stati...

  • juc学习思考

    问题 java高并发学习几次,也读过java高并发编程艺术、设计模式等。还是不够深入,经过2年成长 解决方案

  • java并发编程,volatile关键字解析

    在研究android单例模式时,找到的一篇关于java并发编程的资料,里面比较详细地讲述了java并发编程的概念和...

网友评论

      本文标题:Java并发案例05---Master-Worker模式

      本文链接:https://www.haomeiwen.com/subject/soijmxtx.html