Java多线程Master-Worker模式
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模式的更多相关文章
- java 多线程 发布订阅模式:发布者java.util.concurrent.SubmissionPublisher;订阅者java.util.concurrent.Flow.Subscriber
1,什么是发布订阅模式? 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者).而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话 ...
- java多线程 生产者消费者模式
package de.bvb; /** * 生产者消费者模式 * 通过 wait() 和 notify() 通信方法实现 * */ public class Test1 { public static ...
- Java多线程系列——从菜鸟到入门
持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...
- Java多线程编程中Future模式的详解
Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...
- Java多线程学习笔记--生产消费者模式
实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...
- java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-【费元星Q9715234】
java+反射+多线程+生产者消费者模式+读取xml(SAX)入数据库mysql-[费元星Q9715234] 说明如下,不懂的问题直接我[费元星Q9715234] 1.反射的意义在于不将xml tag ...
- Java多线程Future模式
Java多线程Future模式有些类似于Ajax的异步请求Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 假设服务器的处理某个业务,该业务可以分 ...
- Java多线程--并行模式与算法
Java多线程--并行模式与算法 单例模式 虽然单例模式和并行没有直接关系,但是我们经常会在多线程中使用到单例.单例的好处有: 对于频繁使用的对象可以省去new操作花费的时间: new操作的减少,随之 ...
- 【多线程】java多线程实现生产者消费者模式
思考问题: 1.为什么用wait()+notify()实现生产者消费者模式? wait()方法可以暂停线程,并释放对象锁 notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了s ...
随机推荐
- httpd2.2配置文件详解
httpd2.2官方配置手册:http://httpd.apache.org/docs/2.2/ 注意:关闭防火墙,iptables规则 vim /etc/sysconfig/selinux SELI ...
- HDU 1754 I Hate It(线段树区间求最值)
很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老师有 ...
- 【转】python os.popen 超时问题
python 版本 2.5.4 (在高版本python中提倡使用 subprocess.Popen 取代 os.popen) os.popen 会出现过长时间等待导致阻塞问题, 解决方法如下: [py ...
- c#中常量、ReadOnly和Static ReadOnly的差异
不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: http://www.arungudelli.com/tutorial ...
- Win10系统下安装Ubuntu16.04.3教程与设置
在Win10上刚刚装好Ubuntu16.04.3,装了不下于10次,期间出现很多问题,趁着还有记忆,写下这篇教程,里面还有Ubuntu系统的优化与Win10的一些设置. Part 1 制作Ubuntu ...
- 图片与字符串(base64编码)的转化
package com.demo; import java.util.*; import java.io.*; import sun.misc.BASE64Decoder; import sun.mi ...
- Python数据分析(二): Pandas技巧 (1)
第一部分: ipython http://www.cnblogs.com/cgzl/p/7623347.html 第二部分: numpy http://www.cnblogs.com/cgzl/p/7 ...
- 近期面试总结(PHP后端开发工程师)(部分笔试题)
1.字符串"0"在PHP和js中转换为布尔值是false还是true php:false; php 弱语言 '0'和0一样: js:true:字符串除了空字符串('')其他都是tr ...
- C# TextBlock 上标
我需要做一个函数,显示 ,但是看起来用 TextBlock 做的不好看. 我用 WPF 写的上标看起来不好看,但是最后有了一个简单方法让他好看. 本文告诉大家如何做一个好看的上标. 一开始做的方法: ...
- Java8之旅(六) -- 使用lambda实现尾递归
前言 本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用.众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类 ...