Detailed Explanation of Master-Worker Mode in Java Multithread Programming

Keywords: Java Programming

In Java multithreaded programming, the commonly used multithreaded design patterns include: Future mode, Master-Worker mode, Guarded Suspeionsion mode, invariant mode and producer-consumer mode. This article focuses on the Master-Worker pattern. The addresses for other multithreaded design patterns are as follows:
The addresses for other multithreaded design patterns are as follows:
Detailed explanations of the Future model: Detailed Explanation of Future Mode in Java Multithread Programming
Detailed explanation of the Guarded Suspeionion pattern: Detailed Explanation of Guarded Suspeionsion Mode in Java Multithread Programming
Detailed explanations of invariant patterns: Detailed Explanation of Invariant Patterns in Java Multithread Programming
Detailed explanation of the producer-consumer model: Producer-consumer pattern Java in detail

1 Master-Worker Model Core Ideas

Master-Worker mode is one of the commonly used parallel modes. Its core idea is that the system works together by two kinds of processes: Master process and Worker process. Master is responsible for receiving and assigning tasks, and Wroker is responsible for handling sub-tasks. When each Worker process completes the sub-task processing, the results are returned to the Master process, which aggregates the final results. The specific process is shown in the following figure.

Master process is the main process, which maintains a Worker process queue, sub-task queue and sub-result set. The Worker process in the Worker process queue constantly extracts the subtasks to be processed from the task queue and writes the results to the result set.


Code Implementation of 2 Master-Worker Mode

Class Worker Java Realization

  1. import java.util.Map;  
  2. import java.util.Queue;  
  3.   
  4. public class Worker implements Runnable {  
  5.     //Task queue  
  6.     protected Queue<Object> workQueue;  
  7.     //Subtask Processing Result Set  
  8.     protected Map<String, Object> resultMap;  
  9.     public void setWorkQueue(Queue<Object> workQueue) {  
  10.         this.workQueue = workQueue;  
  11.     }  
  12.   
  13.     public void setResultMap(Map<String, Object> resultMap) {  
  14.         this.resultMap = resultMap;  
  15.     }  
  16.       
  17.     //The logic of sub-task processing is implemented by sub-class instead of concrete implementation.  
  18.     public Object handle(Object input) {  
  19.         return input;  
  20.     }  
  21.       
  22.     @Override  
  23.     public void run() {  
  24.         while(true) {  
  25.             //Getting subtasks  
  26.             Object input = workQueue.poll();  
  27.             if(input == nullbreak;  
  28.             //Handling subtasks  
  29.             Object re = handle(input);  
  30.             //Write the processing results to the result set  
  31.             resultMap.put(Integer.toString(input.hashCode()), re);  
  32.         }  
  33.     }  
  34. }  
Java Implementation of Master Class
  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3. import java.util.Queue;  
  4. import java.util.concurrent.ConcurrentHashMap;  
  5. import java.util.concurrent.ConcurrentLinkedQueue;  
  6.   
  7. public class Master {  
  8.     //Task queue  
  9.     protected Queue<Object> workQueue =   
  10.             new ConcurrentLinkedQueue<Object>();  
  11.     //Worker process queue  
  12.     protected Map<String, Thread> threadMap =   
  13.             new HashMap<String, Thread>();  
  14.     //Subtask Processing Result Set  
  15.     protected Map<String, Object> resultMap =  
  16.             new ConcurrentHashMap<String, Object>();  
  17.       
  18.     public Master(Worker worker, int countWorker) {  
  19.         worker.setWorkQueue(workQueue);  
  20.         worker.setResultMap(resultMap);  
  21.         for(int i=0; i<countWorker; i++) {  
  22.             threadMap.put(Integer.toString(i),   
  23.                     new Thread(worker, Integer.toString(i)));  
  24.         }  
  25.     }  
  26.       
  27.     //Are all subtasks introduced?  
  28.     public boolean isComplete() {  
  29.         for(Map.Entry<String, Thread> entry : threadMap.entrySet()) {  
  30.             if(entry.getValue().getState() != Thread.State.TERMINATED)  
  31.                 //Threads exist for completion  
  32.                 return false;  
  33.         }  
  34.         return true;  
  35.     }  
  36.       
  37.     //Submit a subtask  
  38.     public void submit(Object job) {  
  39.         workQueue.add(job);  
  40.     }  
  41.       
  42.     //Returns the subtask result set  
  43.     public Map<String, Object> getResultMap() {  
  44.         return resultMap;  
  45.     }  
  46.       
  47.     //Execute all Worker processes and process them  
  48.     public void execute() {  
  49.         for(Map.Entry<String, Thread> entry : threadMap.entrySet()) {  
  50.             entry.getValue().start();  
  51.         }  
  52.     }  
  53. }  

Application examples of 3 Master-Worker model

Master-Worker model is used to realize the application of calculating cube sum. Calculate 1 ^ 3 + 2 ^ 3 + 3 ^ 3 +... +100^3.

This computational task is divided into 100 subtasks, each of which is used only to compute individual cubes and sums.

Subclasses of Worker

  1. public class PlusWorker extends Worker { //Cube sum  
  2.     @Override  
  3.     public Object handle(Object input) {  
  4.         int i = (Integer)input;  
  5.         return i * i * i;  
  6.     }  
  7. }  
Function

The call function that runs is as follows. In the main function, four Worker work processes and PlusWorker work instances are created through the Master class. After submitting 100 subtasks, the calculation of subtasks is started. These four processes work together to accomplish these sub-tasks. Master does not wait for all Worker computations to complete before starting to aggregate, but in the process of subtasks, Master begins to aggregate.

  1. import java.util.Map;  
  2. import java.util.Set;  
  3.   
  4. public class Application {  
  5.     public static void main(String[] args) {  
  6.         //Fixed 4 Workde s  
  7.         Master master = new Master(new PlusWorker(), 4);  
  8.         for(int i=1; i<=100; i++) //Submit 100 subtasks  
  9.             master.submit(i);  
  10.         master.execute(); //Start calculation  
  11.           
  12.         Map<String, Object> resultMap = master.getResultMap();  
  13.           
  14.         int re = 0;  //The final calculation results are saved here.  
  15.         //You don't have to wait for all Worker s to be executed.  
  16.         while(true) {  
  17.             Set<String> keys = resultMap.keySet();  //Start calculating the final result  
  18.             String key = null;  
  19.             for(String k : keys) {  
  20.                 key = k;  
  21.                 break;  
  22.             }  
  23.             Integer i = null;  
  24.             if(key != null)  
  25.                 i = (Integer)resultMap.get(key);  
  26.             if(i != null)  
  27.                 re += i; //final result  
  28.             if(key != null)  
  29.                 resultMap.remove(key); //Remove items that have been computed  
  30.             if(master.isComplete() && resultMap.size()==0)  
  31.                 break;  
  32.         }  
  33.         System.out.println(re);  
  34.     }  
  35. }  
The results are as follows:



This article is finished. Please indicate the source for reprinting.

Reference
Ge Yiming, Java Programming Performance Optimization. Tsinghua University Press.

Posted by goclimb on Sun, 14 Apr 2019 11:27:32 -0700