【Java多線程】Java的MapReduce框架ForkJoin

    Fork/Join框架是Java7提供了的一個用於並行執行任務的框架, 是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。

    Fork就是把一個大任務切分爲若干子任務並行的執行。類似MapReduce裏面的Map。

    Join就是合併這些子任務的執行結果,最後得到這個大任務的結果。類似MapReduce裏面的Reduce。

    

    舉例說明,統計1~100的和,並行運行, 每個線程計算20個數的,如果當前線程統計的數量多於20,就切分爲兩個線程運行,切分點爲中間數,至少分配的每一個線程的統計數小於或等於20,這個分裂任務的過程就叫做Fork。最後各個線程向上彙報彙總結果,這個匯聚結果的過程就叫做Join。


    流程圖如下:

21.png



    代碼如下:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.atomic.AtomicInteger;

class Calculator extends RecursiveTask<Integer> 
{  
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    /**
     * 線程計數器
     */
    public static AtomicInteger tcounter = new AtomicInteger(0);
    /**
     * 計算閥值
     */
    private static final int THRESHOLD = 20;  
    /**
     * 開始值
     */
    private int start;
    /**
     * 結束值
     */
    private int end;  
  
    public Calculator(int start, int end) 
    {  
        this.start = start;  
        this.end = end;  
    }  
  
    @Override  
    protected Integer compute() 
    { 
    	tcounter.incrementAndGet();
    	System.out.println("start:" + start + ", end:" + end);
    	
        int sum = 0;  
        if((end - start) <= THRESHOLD)
        {  
        	/**
        	 * 小於等於閥值,直接計算
        	 */
            for(int i = start; i<= end; i++)
            {  
                sum += i;  
            }
        }
        else
        {  
        	/**
        	 * 大於閥值,任務分解, 並匯聚結果
        	 */
            int middle = (start + end) / 2;  
            Calculator left = new Calculator(start, middle);  
            Calculator right = new Calculator(middle + 1, end);  

            left.fork();
            right.fork();
           
            sum = left.join() + right.join();  
        } 
        
        return sum;  
    }  
  
}  

public class TestForkJoinPool 
{
	public static void main(String[] args) throws InterruptedException, ExecutionException 
	{
	    ForkJoinPool forkJoinPool = new ForkJoinPool();  
	    Future<Integer> result = forkJoinPool.submit(new Calculator(1, 100));  
	    System.out.println("結果: " + result.get() + ", " + Calculator.tcounter + "個線程參與了運算");
	}
}

 執行結果

start:1, end:100
start:1, end:50
start:51, end:100
start:1, end:25
start:1, end:13
start:26, end:50
start:14, end:25
start:51, end:75
start:26, end:38
start:39, end:50
start:51, end:63
start:64, end:75
start:76, end:100
start:76, end:88
start:89, end:100
結果: 5050, 15個線程參與了運算

 


    聊聊核心類

    ForkJoinPool:負責建立一個ForkJoin運行環境

    ForkJoinTask: 表示實際運行的任務,一般使用它的兩個子類,一個是RecursiveAction(任務不帶返回值時使用),另一個是RecursiveTask(任務帶返回值時使用)。按照情況選擇任意一個, 使用時需要繼承該子類,然後實現抽象方法compute【任務的邏輯就在compute方法裏編寫】。

 ForkJoinTask.fork方法表示分裂任務, ForkJoinTask.join表示匯聚分裂任務的compute方法的執行結果。

    

   


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章