Java多线程Master-Worker模式,多适用于需要大量重复工作的场景中。

例如:使用Master-Worker计算0到100所有数字的立方的和

  1.Master接收到100个任务,每个任务需要0到100中每个数字的立方,这里为了效果,每个任务再sleep一秒,

   Master需要将这些任务放到一个支持高并发的非阻塞队列queue中如:ConcurrentLinkedQueue<E>。

  2.Master创建10个worker去执行这100个任务,并准备一个支持高并发且线程安全的hashMap作为结果集的容器如:ConcurrentHashMap。

  3.每个worker需要循环的从queue中获取任务然后执行,执行完毕后把结果放到hashMap中,直到queue为空,所有任务执行完毕后退出。

  4.Master循环判断结果集hashMap中是否有已经执行完毕的结果,如果有就使用,使用完毕就立即移除该结果,直到所有的线程都退出。

  5.所有任务执行完毕,Master也处理完所有任务的结果,程序结束

Master不需要等待所有的任务执行完毕就可以处理已完成的任务结果,Master和worker可以同时进行工作,这样节省了大量等待worker执行结束的时间

Master源码

package masterWorker;

import java.lang.Thread.State;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue; import org.junit.Test; public class Master {
public static void main(String[] args) {
long befor = System.currentTimeMillis(); //任务队列
Queue<Integer> taskQueue = new ConcurrentLinkedQueue<>();
//工人map
Map<String,Thread> workers = new HashMap<>();
//结果集
Map<String,Long> resultMap = new ConcurrentHashMap<>();
//最终结果
long result = 0; //提交100个任务
for (int i = 0; i < 100; i++) {
taskQueue.add(i);
} //添加10个工人
for (int i = 0; i < 10; i++) {
workers.put(i+"", new Thread(new Worker(taskQueue,resultMap),"工人"+i));
} //启动所有工人线程
Collection<Thread> threads = workers.values();
for (Thread thread : threads) {
thread.start();
} while(resultMap.size() > 0 || !isComplete(workers)){
Set<String> keySet = resultMap.keySet(); //每次从resultMap中取一个结果出来进行使用
String key = null;
for (String string : keySet) {
if(string != null){
key = string;
break;
}
}
Long value = null;
if(key != null){
value = resultMap.get(key);
} //能取到结果就使用,没有结果继续循环
if(value != null){
//获取到一个运算结果就使用
result = result+value;
//使用后从结果集中移除
resultMap.remove(key);
} }
long after = System.currentTimeMillis();
System.out.println("结果耗时:"+(after - befor));
System.out.println(result); } /**
* 判断所有的工人是否已经完成工作
* @param workers
* @return
*/
private static boolean isComplete(Map<String,Thread> workers){
for (Entry<String, Thread> entry : workers.entrySet()) {
if(entry.getValue().getState() != State.TERMINATED){
return false;
}
}
return true;
} @Test
public void test() throws InterruptedException{
long befor = System.currentTimeMillis();
long result = 0; for (int i = 0; i < 100; i++) { long cube = i*i*i;
result = result+cube;
Thread.sleep(100); }
long after = System.currentTimeMillis();
System.out.println("结果耗时:"+(after - befor));
System.out.println(result);
}
}

  

  

Worker源码

package masterWorker;

import java.util.Map;
import java.util.Queue; public class Worker implements Runnable{
private Queue<Integer> queue;
private Map<String,Long> resultMap; public Worker(Queue<Integer> queue,Map<String,Long> resultMap) {
this.queue = queue;
this.resultMap = resultMap;
} @Override
public void run() {
//不断循环从队列中取出任务进行运算,直到队列为空
while(true){
if(queue.peek() != null){
String name = Thread.currentThread().getName();
int poll =(int) queue.poll();
long result = poll*poll*poll;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
resultMap.put(poll+"", result);
System.out.println(name+"完成"+poll+"的运算,结果为:"+result);
}else{
break;
}
}
}
}

  

经典的Master-Worker源码实例

package masterWorker.classics;
import java.util.Map;
import java.util.Set; public class Main { /**
* @param args
*/
public static void main(String[] args) {
//固定使用5个Worker,并指定Worker
Master m = new Master(new PlusWorker(), Runtime.getRuntime().availableProcessors());
//提交100个子任务
for(int i=0;i<100;i++){
m.submit(i);
}
//开始计算
m.execute();
int re= 0;
//保存最终结算结果
Map<String ,Object> resultMap =m.getResultMap(); //不需要等待所有Worker都执行完成,即可开始计算最终结果
while(resultMap.size()>0 || !m.isComplete()){
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);
} }
System.out.println(re);
} } package masterWorker.classics;
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);
}
} } package masterWorker.classics;
public class PlusWorker extends Worker { @Override
public Object handle(Object input) { Integer i =(Integer)input;
return i*i*i;
} } package masterWorker.classics;
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(); }
} }

  

Java多线程Master-Worker模式的更多相关文章

  1. java 多线程 发布订阅模式:发布者java.util.concurrent.SubmissionPublisher;订阅者java.util.concurrent.Flow.Subscriber

    1,什么是发布订阅模式? 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者).而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话 ...

  2. java多线程 生产者消费者模式

    package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...

  3. Java多线程系列——从菜鸟到入门

    持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...

  4. Java多线程编程中Future模式的详解

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

  5. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

  6. java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】

    java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...

  7. Java多线程Future模式

    Java多线程Future模式有些类似于Ajax的异步请求Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 假设服务器的处理某个业务,该业务可以分 ...

  8. Java多线程--并行模式与算法

    Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例.单例的好处有: 对于频繁使用的对象可以省去new操作花费的时间: new操作的减少,随之 ...

  9. 【多线程】java多线程实现生产者消费者模式

    思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...

随机推荐

  1. Kafka快速上手(2017.9官方翻译)

    为了帮助国人更好了解.上手kafka,特意翻译.修改了个文档.官方Wiki : http://kafka.apache.org/quickstart 快速开始 本教程假定您正在开始新鲜,并且没有现有的 ...

  2. vim与sublime,程序员的屠龙刀和倚天剑

    对程序员来说,写代码是再熟悉不过的事情了,windows系统自带有记事本软件,能写写小规模的代码,可是代码量大了,它的局限性就暴露得很明显了:没有语法高亮,没有自动提示,不支持项目管理,界面难看-- ...

  3. .NET十年回顾

    一.   引子 从我还是编程菜鸟时起,.NET就从来没让我失望过.总是惊喜不断. 当年我第一个项目是做个进销存.用的Winform.当时我是机电工程师.编程只是业余心血来潮而已. .NET的低门槛.V ...

  4. JQ判断浏览器以及版本

    JQuery 使用jQuery.browser 来判断浏览器,返回值可以为: safari(safari) opera(Opera) msie(IE) mozilla(Firefox). if($.b ...

  5. Ubuntu 14.04 安装 Sublime Text 3

    1. 实验环境 Ubuntu 14.04 + Sublime text 3 2. sublime text介绍 ublime Text 是一款流行的文本编辑器软件,有点类似于TextMate,跨平台, ...

  6. ZOJ 2002 Copying Books 二分 贪心

    传送门:Zoj2002 题目大意:从左到右把一排数字k分,得到最小化最大份,如果有多组解,左边的尽量小. 思路:贪心+二分(参考青蛙过河). 方向:从右向左. 注意:有可能最小化时不够k分.如     ...

  7. Java API 常用类(一)

    Java API 常用类 super类详解 "super"关键字代表父类对象.通过使用super关键字,可以访问父类的属性或方法,也可以在子类构造方法中调用父类的构造方法,以便初始 ...

  8. Elasticsearch分片、副本与路由(shard replica routing)

    本文讲述,如何理解Elasticsearch的分片.副本和路由策略. 1.预备知识 1)分片(shard) Elasticsearch集群允许系统存储的数据量超过单机容量,实现这一目标引入分片策略sh ...

  9. php 变量 循环关键词以及方法

    <?php/* 多行注释 */常用数据类型int string double/float bool变量的定义$a = 123;$b = "123";$c = '456';$d ...

  10. Intel Core Microarchitecture Pipeline

    Intel微处理器近20年从Pentium发展到Skylake,得益于制作工艺上的巨大发展,处理器的性能得到了非常大的增强,功能模块增多,不过其指令处理pipeline的主干部分算不上有特别大的变化, ...