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源码

  1. package masterWorker;
  2.  
  3. import java.lang.Thread.State;
  4. import java.util.Collection;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. import java.util.Map.Entry;
  8. import java.util.Queue;
  9. import java.util.Set;
  10. import java.util.concurrent.ConcurrentHashMap;
  11. import java.util.concurrent.ConcurrentLinkedQueue;
  12.  
  13. import org.junit.Test;
  14.  
  15. public class Master {
  16. public static void main(String[] args) {
  17. long befor = System.currentTimeMillis();
  18.  
  19. //任务队列
  20. Queue<Integer> taskQueue = new ConcurrentLinkedQueue<>();
  21. //工人map
  22. Map<String,Thread> workers = new HashMap<>();
  23. //结果集
  24. Map<String,Long> resultMap = new ConcurrentHashMap<>();
  25. //最终结果
  26. long result = 0;
  27.  
  28. //提交100个任务
  29. for (int i = 0; i < 100; i++) {
  30. taskQueue.add(i);
  31. }
  32.  
  33. //添加10个工人
  34. for (int i = 0; i < 10; i++) {
  35. workers.put(i+"", new Thread(new Worker(taskQueue,resultMap),"工人"+i));
  36. }
  37.  
  38. //启动所有工人线程
  39. Collection<Thread> threads = workers.values();
  40. for (Thread thread : threads) {
  41. thread.start();
  42. }
  43.  
  44. while(resultMap.size() > 0 || !isComplete(workers)){
  45. Set<String> keySet = resultMap.keySet();
  46.  
  47. //每次从resultMap中取一个结果出来进行使用
  48. String key = null;
  49. for (String string : keySet) {
  50. if(string != null){
  51. key = string;
  52. break;
  53. }
  54. }
  55. Long value = null;
  56. if(key != null){
  57. value = resultMap.get(key);
  58. }
  59.  
  60. //能取到结果就使用,没有结果继续循环
  61. if(value != null){
  62. //获取到一个运算结果就使用
  63. result = result+value;
  64. //使用后从结果集中移除
  65. resultMap.remove(key);
  66. }
  67.  
  68. }
  69. long after = System.currentTimeMillis();
  70. System.out.println("结果耗时:"+(after - befor));
  71. System.out.println(result);
  72.  
  73. }
  74.  
  75. /**
  76. * 判断所有的工人是否已经完成工作
  77. * @param workers
  78. * @return
  79. */
  80. private static boolean isComplete(Map<String,Thread> workers){
  81. for (Entry<String, Thread> entry : workers.entrySet()) {
  82. if(entry.getValue().getState() != State.TERMINATED){
  83. return false;
  84. }
  85. }
  86. return true;
  87. }
  88.  
  89. @Test
  90. public void test() throws InterruptedException{
  91. long befor = System.currentTimeMillis();
  92. long result = 0;
  93.  
  94. for (int i = 0; i < 100; i++) {
  95.  
  96. long cube = i*i*i;
  97. result = result+cube;
  98. Thread.sleep(100);
  99.  
  100. }
  101. long after = System.currentTimeMillis();
  102. System.out.println("结果耗时:"+(after - befor));
  103. System.out.println(result);
  104. }
  105. }

  

  

Worker源码

  1. package masterWorker;
  2.  
  3. import java.util.Map;
  4. import java.util.Queue;
  5.  
  6. public class Worker implements Runnable{
  7. private Queue<Integer> queue;
  8. private Map<String,Long> resultMap;
  9.  
  10. public Worker(Queue<Integer> queue,Map<String,Long> resultMap) {
  11. this.queue = queue;
  12. this.resultMap = resultMap;
  13. }
  14.  
  15. @Override
  16. public void run() {
  17. //不断循环从队列中取出任务进行运算,直到队列为空
  18. while(true){
  19. if(queue.peek() != null){
  20. String name = Thread.currentThread().getName();
  21. int poll =(int) queue.poll();
  22. long result = poll*poll*poll;
  23. try {
  24. Thread.sleep(100);
  25. } catch (InterruptedException e) {
  26. e.printStackTrace();
  27. }
  28. resultMap.put(poll+"", result);
  29. System.out.println(name+"完成"+poll+"的运算,结果为:"+result);
  30. }else{
  31. break;
  32. }
  33. }
  34. }
  35. }

  

经典的Master-Worker源码实例

  1. package masterWorker.classics;
  2. import java.util.Map;
  3. import java.util.Set;
  4.  
  5. public class Main {
  6.  
  7. /**
  8. * @param args
  9. */
  10. public static void main(String[] args) {
  11. //固定使用5个Worker,并指定Worker
  12. Master m = new Master(new PlusWorker(), Runtime.getRuntime().availableProcessors());
  13. //提交100个子任务
  14. for(int i=0;i<100;i++){
  15. m.submit(i);
  16. }
  17. //开始计算
  18. m.execute();
  19. int re= 0;
  20. //保存最终结算结果
  21. Map<String ,Object> resultMap =m.getResultMap();
  22.  
  23. //不需要等待所有Worker都执行完成,即可开始计算最终结果
  24. while(resultMap.size()>0 || !m.isComplete()){
  25. Set<String> keys = resultMap.keySet();
  26. String key =null;
  27. for(String k:keys){
  28. key=k;
  29. break;
  30. }
  31. Integer i =null;
  32. if(key!=null){
  33. i=(Integer)resultMap.get(key);
  34. }
  35. if(i!=null){
  36. //最终结果
  37. re+=i;
  38. }
  39. if(key!=null){
  40. //移除已经被计算过的项
  41. resultMap.remove(key);
  42. }
  43.  
  44. }
  45. System.out.println(re);
  46. }
  47.  
  48. }
  49.  
  50. package masterWorker.classics;
  51. import java.util.Map;
  52. import java.util.Queue;
  53.  
  54. public class Worker implements Runnable{
  55.  
  56. //任务队列,用于取得子任务
  57. protected Queue<Object> workQueue;
  58. //子任务处理结果集
  59. protected Map<String ,Object> resultMap;
  60. public void setWorkQueue(Queue<Object> workQueue){
  61. this.workQueue= workQueue;
  62. }
  63.  
  64. public void setResultMap(Map<String ,Object> resultMap){
  65. this.resultMap=resultMap;
  66. }
  67. //子任务处理的逻辑,在子类中实现具体逻辑
  68. public Object handle(Object input){
  69. return input;
  70. }
  71.  
  72. @Override
  73. public void run() {
  74.  
  75. while(true){
  76. //获取子任务
  77. Object input= workQueue.poll();
  78. if(input==null){
  79. break;
  80. }
  81. //处理子任务
  82. Object re = handle(input);
  83. resultMap.put(Integer.toString(input.hashCode()), re);
  84. }
  85. }
  86.  
  87. }
  88.  
  89. package masterWorker.classics;
  90. public class PlusWorker extends Worker {
  91.  
  92. @Override
  93. public Object handle(Object input) {
  94.  
  95. Integer i =(Integer)input;
  96. return i*i*i;
  97. }
  98.  
  99. }
  100.  
  101. package masterWorker.classics;
  102. import java.util.HashMap;
  103. import java.util.Map;
  104. import java.util.Queue;
  105. import java.util.concurrent.ConcurrentHashMap;
  106. import java.util.concurrent.ConcurrentLinkedQueue;
  107.  
  108. public class Master {
  109.  
  110. // 任务队列
  111. protected Queue<Object> workQueue = new ConcurrentLinkedQueue<Object>();
  112. // Worker进程队列
  113. protected Map<String, Thread> threadMap = new HashMap<String, Thread>();
  114. // 子任务处理结果集
  115. protected Map<String, Object> resultMap = new ConcurrentHashMap<String, Object>();
  116. // 是否所有的子任务都结束了
  117. public boolean isComplete() {
  118. for (Map.Entry<String, Thread> entry : threadMap.entrySet()) {
  119. if (entry.getValue().getState() != Thread.State.TERMINATED) {
  120. return false;
  121. }
  122.  
  123. }
  124. return true;
  125. }
  126.  
  127. // Master的构造,需要一个Worker进程逻辑,和需要Worker进程数量
  128. public Master(Worker worker, int countWorker) {
  129.  
  130. worker.setWorkQueue(workQueue);
  131. worker.setResultMap(resultMap);
  132. for (int i = 0; i < countWorker; i++) {
  133. threadMap.put(Integer.toString(i),
  134. new Thread(worker, Integer.toString(i)));
  135. }
  136.  
  137. }
  138.  
  139. // 提交一个任务
  140. public void submit(Object job) {
  141. workQueue.add(job);
  142. }
  143.  
  144. // 返回子任务结果集
  145. public Map<String, Object> getResultMap() {
  146. return resultMap;
  147. }
  148.  
  149. // 开始运行所有的Worker进程,进行处理
  150. public void execute() {
  151. for (Map.Entry<String, Thread> entry : threadMap.entrySet()) {
  152. entry.getValue().start();
  153.  
  154. }
  155. }
  156.  
  157. }

  

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. 【专章】dp入门

    动态规划(简称dp),可以说是各种程序设计中遇到的第一个坎吧,这篇博文是我对dp的一点点理解,希望可以帮助更多人dp入门. ***实践是检验真理的唯一标准,看再多文章不如自己动手做几道!!!*** 先 ...

  2. [bzoj1066] [SCOI2007] 蜥蜴 - 网络流

    在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个 ...

  3. http://codeforces.com/contest/402/problem/E

    E. Strictly Positive Matrix time limit per test 1 second memory limit per test 256 megabytes input s ...

  4. php使用PHPMailer邮件类发送邮件

    PHPMailer是一个用于发送电子邮件的PHP函数包.它提供的功能包括:*.在发送邮时指定多个收件人,抄送地址,暗送地址和回复地址*.支持多种邮件编码包括:8bit,base64,binary和qu ...

  5. CPU工作方式、多核心、超线程技术详解[转贴]

    CPU是一台电脑的灵魂,决定电脑整体性能.现在的主流CPU都是多核的,有的运用了多线程技术(Hyper-threading,简称HT).多核可能还容易理解些,相信不少玩家都能说出个所以然.但超线程是个 ...

  6. Template7插入动态模板

    要完成的效果如下图 其中下面添加出来的订单号和订单总价可以看作是接口请求的数据 实现步骤: 1 下载template7:https://github.com/nolimits4web/template ...

  7. JavaScript链式调用

    1.什么是链式调用? 这个很容易理解,例如 $('text').setStyle('color', 'red').show(); 一般的函数调用和链式调用的区别:链式调用完方法后,return thi ...

  8. List之Union(),Intersect(),Except() 即并集,交集,差集运算。

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. 【Vue】浅谈Vue(一):从模板语法数据绑定、指令到计算属性

    写在前面 今年前端届比较有意思,从大漠穷秋发表文章比较angular和vue,继而致歉vue作者.社区,从谷歌辞去Angular Developer PM in China一职并且呼吁大家停止各种无谓 ...

  10. Mac使用nginx+rtmp服务器

    一.安装Homebrow 已经安装了brow的可以直接跳过这一步.执行命令 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/H ...