Java ForkJoinPool線程池的使用之并行計算數(shù)組求和實例
更新時間:2025年05月29日 09:50:49 作者:學(xué)亮編程手記
這篇文章主要介紹了Java ForkJoinPool線程池的使用之并行計算數(shù)組求和實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
Java ForkJoinPool線程池的使用之并行計算數(shù)組求和
package com.zhangxueliang.juc; import java.io.IOException; import java.util.Arrays; import java.util.Random; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; import java.util.concurrent.RecursiveTask; public class ForkJoinPoolDemo { static int[] nums = new int[1000000]; static final int MAX_NUM = 50000; static Random r = new Random(); static { for(int i=0; i<nums.length; i++) { nums[i] = r.nextInt(100); } System.out.println("---" + Arrays.stream(nums).sum()); //stream api } static class AddTask extends RecursiveAction { int start, end; AddTask(int s, int e) { start = s; end = e; } @Override protected void compute() { if(end-start <= MAX_NUM) { long sum = 0L; for(int i=start; i<end; i++) sum += nums[i]; System.out.println("from:" + start + " to:" + end + " = " + sum); } else { int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle); AddTask subTask2 = new AddTask(middle, end); subTask1.fork(); subTask2.fork(); } } } static class AddTaskRet extends RecursiveTask<Long> { private static final long serialVersionUID = 1L; int start, end; AddTaskRet(int s, int e) { start = s; end = e; } @Override protected Long compute() { if(end-start <= MAX_NUM) { long sum = 0L; for(int i=start; i<end; i++) sum += nums[i]; return sum; } int middle = start + (end-start)/2; AddTaskRet subTask1 = new AddTaskRet(start, middle); AddTaskRet subTask2 = new AddTaskRet(middle, end); subTask1.fork(); subTask2.fork(); return subTask1.join() + subTask2.join(); } } public static void main(String[] args) throws IOException { /*ForkJoinPool fjp = new ForkJoinPool(); AddTask task = new AddTask(0, nums.length); fjp.execute(task);*/ ForkJoinPoolDemo temp = new ForkJoinPoolDemo(); ForkJoinPool fjp = new ForkJoinPool(); AddTaskRet task = new AddTaskRet(0, nums.length); fjp.execute(task); long result = task.join(); System.out.println(result); //System.in.read(); } }
ForkJoinPool 示例代碼解析
這段代碼演示了 Java 中 ForkJoinPool
框架的使用,展示了兩種不同的任務(wù)分割方式:
RecursiveAction
(無返回值)RecursiveTask
(有返回值)
代碼結(jié)構(gòu)分析
1. 初始化部分
static int[] nums = new int[1000000]; // 創(chuàng)建包含100萬個元素的數(shù)組 static final int MAX_NUM = 50000; // 任務(wù)分割的閾值 static Random r = new Random(); // 隨機數(shù)生成器 // 靜態(tài)初始化塊:填充數(shù)組并計算總和 static { for(int i=0; i<nums.length; i++) { nums[i] = r.nextInt(100); // 每個元素賦值為0-99的隨機數(shù) } System.out.println("---" + Arrays.stream(nums).sum()); // 使用stream API計算總和作為驗證基準 }
2. RecursiveAction 實現(xiàn)(無返回值)
static class AddTask extends RecursiveAction { int start, end; AddTask(int s, int e) { start = s; end = e; } @Override protected void compute() { if(end-start <= MAX_NUM) { // 如果任務(wù)足夠小,直接計算 long sum = 0L; for(int i=start; i<end; i++) sum += nums[i]; System.out.println("from:" + start + " to:" + end + " = " + sum); } else { // 否則分割任務(wù) int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle); AddTask subTask2 = new AddTask(middle, end); subTask1.fork(); // 異步執(zhí)行子任務(wù) subTask2.fork(); } } }
3. RecursiveTask 實現(xiàn)(有返回值)
static class AddTaskRet extends RecursiveTask<Long> { int start, end; AddTaskRet(int s, int e) { start = s; end = e; } @Override protected Long compute() { if(end-start <= MAX_NUM) { // 如果任務(wù)足夠小,直接計算并返回結(jié)果 long sum = 0L; for(int i=start; i<end; i++) sum += nums[i]; return sum; } // 分割任務(wù) int middle = start + (end-start)/2; AddTaskRet subTask1 = new AddTaskRet(start, middle); AddTaskRet subTask2 = new AddTaskRet(middle, end); subTask1.fork(); // 異步執(zhí)行子任務(wù) subTask2.fork(); return subTask1.join() + subTask2.join(); // 合并子任務(wù)結(jié)果 } }
4. 主方法
public static void main(String[] args) throws IOException { // 創(chuàng)建ForkJoinPool實例 ForkJoinPool fjp = new ForkJoinPool(); // 創(chuàng)建有返回值的任務(wù) AddTaskRet task = new AddTaskRet(0, nums.length); // 執(zhí)行任務(wù) fjp.execute(task); // 獲取并打印結(jié)果 long result = task.join(); System.out.println(result); }
關(guān)鍵概念解釋
ForkJoinPool:
- Java 7引入的線程池實現(xiàn)
- 使用工作竊取(work-stealing)算法提高并行效率
- 特別適合分治(divide-and-conquer)算法
RecursiveAction:
- 用于不返回結(jié)果的任務(wù)
- 需要實現(xiàn)
compute()
方法 - 示例中的
AddTask
只打印結(jié)果不返回
RecursiveTask:
- 用于需要返回結(jié)果的任務(wù)
- 需要實現(xiàn)
compute()
方法并返回指定類型 - 示例中的
AddTaskRet
返回子數(shù)組的和
fork()和join():
fork()
: 異步安排任務(wù)執(zhí)行join()
: 等待任務(wù)完成并獲取結(jié)果
執(zhí)行流程
- 初始化一個包含100萬個隨機數(shù)的數(shù)組
- 使用Stream API計算總和作為基準
- 創(chuàng)建ForkJoinPool
- 創(chuàng)建AddTaskRet任務(wù),范圍是整個數(shù)組
- 任務(wù)會根據(jù)MAX_NUM閾值(50000)不斷分割,直到足夠小
- 小任務(wù)直接計算子數(shù)組和
- 合并所有子任務(wù)的結(jié)果得到最終總和
- 打印結(jié)果(應(yīng)與Stream API計算的結(jié)果一致)
使用建議
- 對于計算密集型任務(wù),F(xiàn)orkJoinPool通常比傳統(tǒng)線程池更高效
- 任務(wù)分割的閾值需要合理設(shè)置,太小會導(dǎo)致過多任務(wù)創(chuàng)建開銷,太大會降低并行度
- 有返回結(jié)果需求時使用RecursiveTask,否則使用RecursiveAction
- 注意join()是阻塞調(diào)用,會等待任務(wù)完成
這段代碼很好地展示了ForkJoin框架的分治思想和使用方法,是并行計算數(shù)組求和的經(jīng)典示例。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java使用mysql預(yù)編譯語句查詢優(yōu)勢及示例詳解
這篇文章主要為大家介紹了java使用mysql預(yù)編譯語句的優(yōu)勢特點及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06RestTemplate在Spring或非Spring環(huán)境下使用精講
這篇文章主要為大家介紹了RestTemplate在Spring或非Spring環(huán)境下使用精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-03-03Java中將String類型轉(zhuǎn)換為int類型的幾種常見方法
在java中經(jīng)常會遇到需要對數(shù)據(jù)進行類型轉(zhuǎn)換的場景,這篇文章主要給大家介紹了關(guān)于Java中將String類型轉(zhuǎn)換為int類型的幾種常見方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2024-07-07