Java併發之Fork-Join

一、Fork-Join 簡介

fork/join 框架是 Java 7 中引入的 ,它是一個工具,通過 「 分而治之 」 的方法嘗試將所有可用的處理器內核使用起來幫助加速並行處理。在實際使用過程中,這種 「 分而治之 」的方法意味着框架首先要 fork ,遞歸地將任務分解爲較小的獨立子任務,直到它們足夠簡單以便異步執行。然後,join 部分開始工作,將所有子任務的結果遞歸地連接成單個結果,或者在返回 void 的任務的情況下,程序只是等待每個子任務執行完畢。

二、ForkJoinPool 線程池

ForkJoinPool 是 fork/join 框架的核心,是 ExecutorService的一個實現,用於管理工作線程,並提供了一些工具來幫助獲取有關線程池狀態和性能的信息(工作竊取( work-stealing )算法)。

三、ForkJoinPool線程池的實例化

(1) 在Java8 中提供 commonPool() 靜態方法

 ForkJoinPool commonPool = ForkJoinPool.commonPool();

(2) 在Java 7中 提供創建ForkJoinPool 的實例化方法

public static ForkJoinPool forkJoinPool = new ForkJoinPool(2);

四、ForkJoinTask 類

ForkJoinTaskForkJoinPool 線程之中執行的任務的基本類型。我們日常使用時,一般不直接使用 ForkJoinTask ,而是擴展它的兩個子類中的任意一個:

1、任務不返回結果 ( 返回 void ) 的 RecursiveAction
2、返回值的任務的 RecursiveTask

這兩個類都有一個抽象方法 compute() ,用於定義任務的邏輯。

(1) RecursiveAction

public class CustomRecursiveAction extends RecursiveAction {

    private String workload = "";
    private static final int THRESHOLD = 4;

    private static Logger logger = 
      Logger.getAnonymousLogger();

    public CustomRecursiveAction(String workload) {
        this.workload = workload;
    }

    @Override
    protected void compute() {
        if (workload.length() > THRESHOLD) {
            ForkJoinTask.invokeAll(createSubtasks());
        } else {
           processing(workload);
        }
    }

    private List<CustomRecursiveAction> createSubtasks() {
        List<CustomRecursiveAction> subtasks = new ArrayList<>();

        String partOne = workload.substring(0, workload.length() / 2);
        String partTwo = workload.substring(workload.length() / 2, workload.length());

        subtasks.add(new CustomRecursiveAction(partOne));
        subtasks.add(new CustomRecursiveAction(partTwo));

        return subtasks;
    }

    private void processing(String work) {
        String result = work.toUpperCase();
        logger.info("This result - (" + result + ") - was processed by "
          + Thread.currentThread().getName());
    }
}

(2) RecursiveTask 類

對於有返回值的任務,除了將每個子任務的結果在一個結果中合併,其它邏輯和 RecursiveAction 都差不多。

public class CustomRecursiveTask extends RecursiveTask<Integer> {
    private int[] arr;

    private static final int THRESHOLD = 20;

    public CustomRecursiveTask(int[] arr) {
        this.arr = arr;
    }

    @Override
    protected Integer compute() {
        if (arr.length > THRESHOLD) {
            return ForkJoinTask.invokeAll(createSubtasks())
              .stream()
              .mapToInt(ForkJoinTask::join)
              .sum();
        } else {
            return processing(arr);
        }
    }

    private Collection<CustomRecursiveTask> createSubtasks() {
        List<CustomRecursiveTask> dividedTasks = new ArrayList<>();
        dividedTasks.add(new CustomRecursiveTask(
          Arrays.copyOfRange(arr, 0, arr.length / 2)));
        dividedTasks.add(new CustomRecursiveTask(
          Arrays.copyOfRange(arr, arr.length / 2, arr.length)));
        return dividedTasks;
    }

    private Integer processing(int[] arr) {
        return Arrays.stream(arr)
          .filter(a -> a > 10 && a < 27)
          .map(a -> a * 10)
          .sum();
    }
}

五、 將任務提交到 ForkJoinPool 線程池中

(1) submit() 方法

forkJoinPool.submit(customRecursiveTask);
int result = customRecursiveTask.join();

(2) execute 方法

forkJoinPool.execute(customRecursiveTask);
int result = customRecursiveTask.join();

(3) 使用 invoke() 或 invokeAll( ) 方法 fork 任務並等待結果,不需要任何手動連接 ( join )

int result = forkJoinPool.invoke(customRecursiveTask);

當涉及到多個任務且要保證任務的順序時,通常都是使用 ForkJoinPool.invokeAll()

(4)最終執行程序

package day01;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.logging.Logger;


/**
 *  fork-Join方法實現
 *  @author zc
 *
 */
public class ForkJoinTest  extends RecursiveAction {
	
	
	private static final long serialVersionUID = 1L;
	
	private String workload = "";
	
	private static final int THRESHOLD = 4;

	  private static Logger logger = 
		      Logger.getAnonymousLogger();

     public ForkJoinTest(String workload) {
		        this.workload = workload;
	}
     
	@Override
	protected void compute() {
	
		 if (workload.length() > THRESHOLD) {
	            ForkJoinTask.invokeAll(createSubtasks());
	       }else {
	           processing(workload);
	      }
		
	}
	 private List<ForkJoinTest> createSubtasks() {
	        List<ForkJoinTest> subtasks = new ArrayList<>();

	        String partOne = workload.substring(0, workload.length() / 2);
	        String partTwo = workload.substring(workload.length() / 2, workload.length());

	        subtasks.add(new ForkJoinTest(partOne));
	        subtasks.add(new ForkJoinTest(partTwo));

	        return subtasks;
	    }

	    private void processing(String work) {
	        String result = work.toUpperCase();
	        logger.info("This result - (" + result + ") - was processed by "
	          + Thread.currentThread().getName());
	    }
	
	public static void main(String[] args) {
		
		// (1) ForkJoinPool實例化方式一
		ForkJoinPool commonPool =ForkJoinPool.commonPool();
		
		// (2) ForkJoinPool實例化方式二, 2代表兩個處理單元
		 ForkJoinPool forkJoinPool =new  ForkJoinPool(2);
		 
		 
		 ForkJoinTest forkJoin = new  ForkJoinTest("tewrerefedewrewr");

		 
		 commonPool.submit(forkJoin);
		 
		 //執行計算結果
		 forkJoin.join();
		 
		 
	}

	

}

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