java分治思想之ForkJoin詳解
前言
當(dāng)我們面對(duì)需要同時(shí)執(zhí)行多個(gè)任務(wù)的情況時(shí),往往需要耗費(fèi)大量的時(shí)間和精力來編寫復(fù)雜的并發(fā)代碼。但是有一種技術(shù)可以幫助我們輕松地處理這種情況。通過forkJoin,我們可以簡單地實(shí)現(xiàn)多個(gè)任務(wù)的并行執(zhí)行,從而提高應(yīng)用程序的性能和響應(yīng)能力。在本文中,我們將深入探討forkJoin的工作原理和使用方法。
分治思想算法
fork-join模式是基于分治思想的并行計(jì)算模式之一。該模式將一個(gè)大的任務(wù)分割成多個(gè)小的子任務(wù),然后并行執(zhí)行這些子任務(wù),最后將它們的結(jié)果合并起來得到最終的結(jié)果。在這個(gè)過程中,每個(gè)子任務(wù)的執(zhí)行可以進(jìn)一步分解為更小的子任務(wù),直到達(dá)到某個(gè)閾值,這時(shí)候任務(wù)將被串行執(zhí)行。這種遞歸的分治思想使得fork-join模式可以有效地利用計(jì)算機(jī)的多核處理能力,從而提高程序的性能和效率。
歸并排序
歸并排序是一種基于分治思想的排序算法。其核心思想是將一個(gè)數(shù)組分成兩個(gè)子數(shù)組,分別對(duì)其進(jìn)行排序后再將其合并起來。具體實(shí)現(xiàn)過程如下:
- 分解:將一個(gè)數(shù)組分成兩個(gè)子數(shù)組,分別對(duì)其進(jìn)行排序??梢允褂眠f歸來實(shí)現(xiàn)這一步驟。
- 合并:將排序后的兩個(gè)子數(shù)組合并成一個(gè)有序的數(shù)組。
- 遞歸:對(duì)兩個(gè)子數(shù)組遞歸進(jìn)行分解和排序,直到每個(gè)子數(shù)組的長度為1。
時(shí)間復(fù)雜度為O(nlogn)。
public class Merge { public static void main(String[] args) { int[] arr = { 5, 2, 8, 4, 7, 1, 3, 6 }; mergeSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } /** * 拆分 * @param arr 數(shù)組 * @param left 數(shù)組第一個(gè)元素 * @param right 數(shù)組最后一個(gè)元素 */ public static void mergeSort(int[] arr,int left,int right){ if (left < right) { int mid = (left + right) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); merge(arr, left, mid, right); } } /** * 合并 * @param arr 數(shù)組 * @param left 數(shù)組第一個(gè)元素 * @param mid 數(shù)組分割的元素 * @param right 數(shù)組最后一個(gè)元素 */ public static void merge(int[] arr,int left,int mid,int right){ //創(chuàng)建臨時(shí)數(shù)組,用于存放合并后的數(shù)組 int[] temp = new int[right - left + 1]; //左面數(shù)組的起始指針 int i = left; //右面數(shù)組的起始指針 int j = mid + 1; //臨時(shí)數(shù)組的下標(biāo) int k = 0; //數(shù)組左面和數(shù)組右面都還有值就去遍歷比較賦值 while (i <= mid && j <= right) { //數(shù)組左面的值小于或者等于數(shù)組右面的值就把左面的值賦值到臨時(shí)數(shù)組中 //并且把左面的指針和臨時(shí)數(shù)組的指針+1 //否則相反 if (arr[i] <= arr[j]) { temp[k] = arr[i]; k++; i++; } else { temp[k] = arr[j]; k++; j++; } } //把剩余數(shù)組塞進(jìn)去 while (i <= mid) { temp[k] = arr[i]; k++; i++; } while (j <= right) { temp[k] = arr[j]; k++; j++; } //講臨時(shí)數(shù)組中的元素拷貝會(huì)回原數(shù)組中 for (int p = 0; p < temp.length; p++) { arr[left + p] = temp[p]; } } }
快速排序
快速排序(Quick Sort)是一種基于分治思想的排序算法,它采用了遞歸的方式將一個(gè)大的數(shù)組分解成多個(gè)子數(shù)組,分別進(jìn)行排序后再將它們合并起來。其基本思想是選取一個(gè)基準(zhǔn)元素,將數(shù)組中小于該元素的值放在左邊,大于該元素的值放在右邊,然后遞歸地對(duì)左右兩個(gè)子數(shù)組進(jìn)行排序。具體的步驟如下:
- 選取一個(gè)基準(zhǔn)元素(通常是數(shù)組中的第一個(gè)元素)。
- 將數(shù)組中小于該元素的值放在左邊,大于該元素的值放在右邊。
- 對(duì)左右兩個(gè)子數(shù)組分別遞歸進(jìn)行快速排序。
- 合并左右兩個(gè)已排序的子數(shù)組。
快速排序的時(shí)間復(fù)雜度為O(nlogn),它是一種原地排序算法,不需要額外的存儲(chǔ)空間,因此空間復(fù)雜度為O(1)。雖然快速排序的最壞時(shí)間復(fù)雜度為O(n^2),但是在實(shí)際應(yīng)用中,快速排序的平均時(shí)間復(fù)雜度和最好時(shí)間復(fù)雜度均為O(nlogn),因此是一種非常高效的排序算法
public class QuickSort { public static void main(String[] args) { int[] arr = { 5, 2, 8, 4, 7, 1, 3, 6 }; quickSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } public static void quickSort(int[] arr,int left,int right){ if(left<right){ int pivotIndex = partition(arr, left, right); quickSort(arr,left,pivotIndex-1); quickSort(arr,pivotIndex+1,right); } } public static int partition(int[] arr,int left,int right){ //取第一個(gè)元素為基準(zhǔn)元素 int pivot = arr[left]; int i = left+1; int j = right; while (i<=j){ //當(dāng)前指針位置數(shù)小于基準(zhǔn)元素就繼續(xù)移動(dòng)指針直到遇到大的 while (i<=j && arr[i] < pivot){ i++; } //當(dāng)前指針位置數(shù)大于基準(zhǔn)元素就繼續(xù)移動(dòng)指針直到遇到小的 while (i<=j && arr[j] > pivot){ j--; } if(i<j){ //交換元素位置 swap(arr,i,j); i++; j--; } } //跳出循環(huán)說明i和j相遇,j的值一定是大于基準(zhǔn)元素,要和基準(zhǔn)元素進(jìn)行交換 swap(arr,left,j); //返回基準(zhǔn)元素位置 return j; } public static void swap(int[] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } }
Fork/Join
Fork/Join框架的主要組成部分是ForkJoinPool、ForkJoinTask。ForkJoinPool是一個(gè)線程池,它用于管理ForkJoin任務(wù)的執(zhí)行。ForkJoinTask是一個(gè)抽象類,用于表示可以被分割成更小部分的任務(wù)。
ForkJoinPool
ForkJoinPool是Fork/Join框架中的線程池類,它用于管理Fork/Join任務(wù)的線程。ForkJoinPool類包括一些重要的方法,例如submit()、invoke()、shutdown()、awaitTermination()等,用于提交任務(wù)、執(zhí)行任務(wù)、關(guān)閉線程池和等待任務(wù)的執(zhí)行結(jié)果。ForkJoinPool類中還包括一些參數(shù),例如線程池的大小、工作線程的優(yōu)先級(jí)、任務(wù)隊(duì)列的容量等,可以根據(jù)具體的應(yīng)用場(chǎng)景進(jìn)行設(shè)置。
構(gòu)造器
ForkJoinPool中有四個(gè)核心參數(shù),用于控制線程池的并行數(shù)、工作線程的創(chuàng)建、異常處理和模式指定等。
- int parallelism:指定并行級(jí)別(parallelism level)。ForkJoinPool將根據(jù)這個(gè)設(shè)定,決定工作線程的數(shù)量。如果未設(shè)置的話,將使用Runtime.getRuntime().availableProcessors()來設(shè)置并行級(jí)別;
- ForkJoinWorkerThreadFactory factory:ForkJoinPool在創(chuàng)建線程時(shí),會(huì)通過factory來創(chuàng)建。注意,這里需要實(shí)現(xiàn)的是ForkJoinWorkerThreadFactory,而不是ThreadFactory。如果你不指定factory,那么將由默認(rèn)的 DefaultForkJoinWorkerThreadFactory負(fù)責(zé)線程的創(chuàng)建工作;
- UncaughtExceptionHandler handler:指定異常處理器,當(dāng)任務(wù)在運(yùn)行中出錯(cuò)時(shí),將由設(shè)定的處理器處理;
- boolean asyncMode:設(shè)置隊(duì)列的工作模式。當(dāng)asyncMode為true時(shí),將使用先進(jìn)先出隊(duì)列,而為false時(shí)則使用后進(jìn)先出的模式。
工作竊取法
在Fork-Join模式中,任務(wù)被分配給一個(gè)線程池中的工作線程來執(zhí)行。當(dāng)一個(gè)工作線程執(zhí)行完自己分配的任務(wù)后,它可以從其他工作線程的任務(wù)隊(duì)列中偷取(Steal)任務(wù)來執(zhí)行,這就是所謂的工作竊?。╓ork Stealing)。
使用
public class SumTask extends RecursiveTask<Integer> { private static final int THRESHOLD = 1000; private int[] array; private int start; private int end; public SumTask(int[] array, int start, int end) { this.array = array; this.start = start; this.end = end; } @Override protected Integer compute() { if (end - start <= THRESHOLD) { int sum = 0; for (int i = start; i < end; i++) { sum += array[i]; } return sum; } else { int mid = (start + end) / 2; SumTask leftTask = new SumTask(array, start, mid); SumTask rightTask = new SumTask(array, mid, end); leftTask.fork(); rightTask.fork(); int leftResult = leftTask.join(); int rightResult = rightTask.join(); return leftResult + rightResult; } } public static void main(String[] args) { int[] array = new int[10000]; for (int i = 0; i < array.length; i++) { array[i] = i + 1; } ForkJoinPool forkJoinPool = new ForkJoinPool(); SumTask task = new SumTask(array, 0, array.length); int result = forkJoinPool.invoke(task); System.out.println(result); } }
以上就是java分治思想之ForkJoin詳解的詳細(xì)內(nèi)容,更多關(guān)于java分治思想ForkJoin的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java調(diào)用微信現(xiàn)金紅包接口的心得與體會(huì)總結(jié)
這篇文章主要介紹了java調(diào)用微信現(xiàn)金紅包接口的心得與體會(huì)總結(jié),有需要的朋友可以了解一下。2016-11-11Springboot實(shí)現(xiàn)ModbusTCP通信的示例詳解
ModbusTCP協(xié)議是Modbus由MODICON公司于1979年開發(fā),是一種工業(yè)現(xiàn)場(chǎng)總線協(xié)議標(biāo)準(zhǔn),本文主要介紹了Springboot實(shí)現(xiàn)ModbusTCP通信的相關(guān)知識(shí),需要的可以參考下2023-12-12Java?Spring?boot實(shí)現(xiàn)生成二維碼
大家好,本篇文章主要講的是Java?Spring?boot實(shí)現(xiàn)生成二維碼,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下2022-02-02java實(shí)現(xiàn)遺傳算法實(shí)例分享(打印城市信息)
本文介紹java實(shí)現(xiàn)遺傳算法的實(shí)例,代碼中使用城市名做為數(shù)據(jù),可以打印當(dāng)前代數(shù)的所有城市序列,以及其相關(guān)的參數(shù),大家參考使用吧2014-01-01mybatis執(zhí)行update批量更新時(shí)報(bào)錯(cuò)的解決方案
這篇文章主要介紹了mybatis執(zhí)行update批量更新時(shí)報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java Web基于Session的登錄實(shí)現(xiàn)方法
這篇文章主要介紹了Java Web基于Session的登錄實(shí)現(xiàn)方法,涉及Java針對(duì)session的操作及表單提交與驗(yàn)證技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10