高併發(7)- 線程併發工具類-Fork/Join

高併發(7)- 線程併發工具類-Fork/Join

前言

    上篇文章講解了線程之間的協作。本篇就進入線程的併發工具類講解。

Fork/Join

一、什麼是Fork/Join
   Fork/Join是Jdk1.7之後提供的多線程併發處理框架,Fork/Join的核心思想就是分而治之。
二、什麼是分而治之
  分而治之就是將一個較爲複雜的計算,按照我們設定好的閾值分解成多個計算,就是將一個大技術拆分成多個子任務(拆分到不可再拆分)處理,然後將一個小小的任務運算結果進行join彙總。  
   Fork/Join流程圖
三、實現
  forkJoin可以實現兩個類
  RecursiveTask代表有返回值的任務,RecursiveAction代表沒有返回值的任務。我們可以根據我們的需求使用具體的方法。
四、代碼實現
  我們定義一個場景,現有一個N長度的數組,我們需要會中數組中的值,通用方法就是循環數組來計算總數,使用 ForkJoin怎麼實現呢,我們來看看下代碼
forkJon具體流程

/**
 * @version 1.0
 * @Description forkJoinDemo
 * @Author wb.yang
 */
public class ForkJoinDemo {

	/**
	 * 數組長度
	 */
	public static final int ARRAY_LENGTH = 100000000;

	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;

	}


	private static class SumTask extends RecursiveTask<Integer> {

		private final static int THRESHOLD = ARRAY_LENGTH / 10;
		private int[] src; //表示我們要實際統計的數組
		private int fromIndex;//開始統計的下標
		private int toIndex;//統計到哪裏結束的下標

		public SumTask(int[] src, int fromIndex, int toIndex) {
			this.src = src;
			this.fromIndex = fromIndex;
			this.toIndex = toIndex;
		}

		@Override
		protected Integer compute() {
			// 判斷數組長度是否到我們的閾值
			if (toIndex - fromIndex < THRESHOLD) {
				int count = 0;
				//循環數組相加數據
				for (int i = fromIndex; i <= toIndex; i++) {
					count = count + src[i];
				}
				return count;
			} else {
				//沒有達到閾值,繼續拆分任務
				int mid = (fromIndex + toIndex) / 2;
				SumTask left = new SumTask(src, fromIndex, mid);
				SumTask right = new SumTask(src, mid + 1, toIndex);
				invokeAll(left, right);
				//組合結果
				return left.join() + right.join();
			}
		}
	}


	public static void main(String[] args) {
		// 創建一個forkJin
		ForkJoinPool pool = new ForkJoinPool();
		//創建數組
		int[] src = makeArray();
		//創建我們自己的任務
		SumTask innerFind = new SumTask(src, 0, src.length - 1);

		long start = System.currentTimeMillis();
		// 同步調用
		pool.invoke(innerFind);
		System.out.println("Task is Running.....");

		System.out.println("The count is " + innerFind.join()
				+ " spend time:" + (System.currentTimeMillis() - start) + "ms");

	}
}

從上面代碼可以看出,我們先創建了一個隨機數生成函數,生成了指定長度的數組,我們的需求就是彙總數組裏面值的總數,通用方法就是循環數組來計算總數,我們使用了forkJoin就是建立一個我們自己任務的類。因爲我們需要彙總,需要返回值,所以需要使用RecursiveTask方法,然後SumTask繼承了RecursiveTask類,重寫了compute方法。
  在compute方法中,我們可以看到進入之後就進行閾值判斷(這個閾值就是我們拆分之後的數組長度),判斷數組長度是否達到了我們的閾值,如果沒有達到閾值的,就需要繼續拆分這個任務,在拆分成小任務,如果達到了我們的閾值之後,就可以將我們的數組裏面的數據進行彙總,然後返回,最後將我們的結果進行join彙總返回。
  ForkJoin執行結果
  從結果中正是打印了執行結果,這個就是使用forkJoin的過程。

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