Java併發程式設計ForkJoin的Demo

張俊傑zjj發表於2020-10-19

前言

時間有限, 就先寫著,有時間補註釋

概念問題在這裡:
https://blog.csdn.net/qq_41489540/article/details/109166650

準備資料來源工具類

使用根據類準備


import java.util.Random;

/**
 * 準備陣列工具類
 */
public class MakeArrayUtil {
	//陣列長度 如果設定過大,會使得計算結果變為負數
 	public static final int ARRAY_LENGTH = 10000;
	public final static int THRESHOLD = 47;

	public static int[] makeArray() {

		//new一個隨機數發生器
		Random r = new Random();
		int[] result = new int[ARRAY_LENGTH];
		for (int i = 0; i < ARRAY_LENGTH; i++) {
			//用隨機數填充陣列
			result[i] = r.nextInt(ARRAY_LENGTH * 3);
		}
		return result;

	}
}

不使用ForkJoin單執行緒累計工作



public class Main {
	public static void main(String[] args) {
		int count = 0;
		int[] src = MakeArrayUtil.makeArray();

		long start = System.currentTimeMillis();
		for (int i = 0; i < src.length; i++) {
			SleepTools.ms(1);
			count = count + src[i];
		}
		System.out.println("總數是 " + count
				+ " 耗時" + (System.currentTimeMillis() - start) + "ms");
	}
}

控制檯列印結果: 總數是 150190419 耗時18051ms

花費了18051ms

使用ForkJoin累計工作

這個資料來源和上面的不使用ForkJoin單執行緒累計工作的類是一個類.所以是一個資料來源


import utils.SleepTools;

import java.util.concurrent.RecursiveTask;

public class SumTask extends RecursiveTask<Integer> {

	/*閾值(拆分到多小的時候不拆分了,直接進行計算) 陣列長度除以10*/
	private final static int THRESHOLD = MakeArrayUtil.ARRAY_LENGTH / 10;
	private int[] src; //原始陣列
	private int fromIndex;
	private int toIndex;

	/**
	 * 構造
	 * @param src       陣列
	 * @param fromIndex 陣列的起始索引
	 * @param toIndex   陣列的最大索引
	 */
	public SumTask(int[] src, int fromIndex, int toIndex) {
		this.src = src;
		this.fromIndex = fromIndex;
		this.toIndex = toIndex;
	}

	/**
	 * 執行計算的方法
	 * @return
	 */
	@Override
	protected Integer compute() {
			/*任務的大小是否合適
				結束索引-起始索引小於閾值了就直接彙總統計
			* */
		if (toIndex - fromIndex < THRESHOLD) {
			int count = 0;
			for (int i = fromIndex; i <= toIndex; i++) {
				SleepTools.ms(1);
				count = count + src[i];
			}
			return count;  // 結果返回出去
		} else {//	大於閾值 就對半拆分


			//fromIndex....mid.....toIndex
			int mid = (fromIndex + toIndex) / 2; //求中間值

			//拆分成兩個
			SumTask left = new SumTask(src, fromIndex, mid);//左半邊
			SumTask right = new SumTask(src, mid + 1, toIndex);//右半邊(注意一定要中間值索引加1)
			invokeAll(left, right);//把左右子任務拿到池子裡面去執行
			return left.join() + right.join();  //拿到兩個子任務的值(左邊加右邊)
		}
	}
}


public class Main {
	/**
	 * 統計陣列的所有的元素的和案例
	 * 用 ForkJoin
	 */
	public static void main(String[] args)  {

		int[] src = MakeArrayUtil.makeArray();
		/*new出池的例項*/
		ForkJoinPool pool = new ForkJoinPool();
		/*new出Task的例項*/
		SumTask innerFind = new SumTask(src, 0, src.length - 1);


		long start = System.currentTimeMillis();
		//開始執行
		Integer invoke = pool.invoke(innerFind); //同步執行 獲取結果,會在計算之後列印下面的話
//		ForkJoinTask<Integer> submit = pool.submit(innerFind); //非同步執行,會在計算完成之前列印下面的話
		System.out.println("執行完成了");

		//System.out.println("Task is Running.....");
		Integer count = innerFind.join();

		System.out.println("總數是 " + count
				+ " 耗時" + (System.currentTimeMillis() - start) + "ms");

	}
}

控制檯列印:
執行完成了
總數是 150759206 耗時2273ms

總結

不使用ForkJoin的情況下耗時18051ms , 使用ForkJoin的情況下耗時2273ms

相關文章