当前位置: 首页 > news >正文

Java 并行编程

Java 并行编程

核心思想

当前计算机多为多CPU、多核架构,为充分发挥硬件性能,可将一个大任务拆分成多个独立小任务。这些小任务在不同处理器核心上并行执行,执行完成后合并结果,最终得到大任务的解决方案。

Fork/Join 框架介绍

JDK7 引入 Fork/Join 框架,专为并行编程设计,是分而治之思想的并行实现。

核心组件

  1. ForkJoinPool:ExecutorService 的实现类,属于特殊线程池,负责执行 ForkJoinTask 任务,通过少量核心线程管理大量任务。
  2. ForkJoinTask:任务抽象基类,类似线程但更轻量级,支持通过 fork() 异步拆分任务、join() 等待任务完成。
  3. 核心子类
    • RecursiveAction:用于定义无返回值的并行任务。
    • RecursiveTask:用于定义有返回值的并行任务,需指定返回值类型。
    • 要定义具体的任务类根据情况继承上面两个子类,自己的任务重写compute()方法来指定任务是如何执行的。

工作流程

  1. 拆分(Fork):大任务递归拆分为多个不重叠的子任务,直到子任务达到阈值(无需再拆分)。
  2. 执行:子任务在 ForkJoinPool 中并行执行。
  3. 合并(Join):收集所有子任务的执行结果,合并为大任务的最终结果。
    image

示例一:归并排序对比(无返回值)

普通(单线程)归并排序

package com.forkjoin;/*** 递归实现归并排序* @author Jing61*/
public class MergeSort {public static void sort(int[] list) {if (list.length <= 1) return;int middle = list.length / 2;int[] firstHalf = new int[middle];System.arraycopy(list, 0, firstHalf, 0, firstHalf.length);sort(firstHalf);int[] secondHalf = new int[list.length - middle];System.arraycopy(list, middle, secondHalf, 0, secondHalf.length);sort(secondHalf);merge(firstHalf, secondHalf, list);}public static void merge(int[] firstHalf, int[] secondHalf, int[] list) {int firstIndex = 0;int secondIndex = 0;int listIndex = 0;while (firstIndex < firstHalf.length && secondIndex < secondHalf.length) {if (firstHalf[firstIndex] < secondHalf[secondIndex]) list[listIndex++] = firstHalf[firstIndex++];else list[listIndex++] = secondHalf[secondIndex++];}while (firstIndex < firstHalf.length) list[listIndex++] = firstHalf[firstIndex++];while (secondIndex < secondHalf.length) list[listIndex++] = secondHalf[secondIndex++];}public static void main(String[] args) {int[] list = new int[]{5, 4, 3, 2, 1};sort(list);for (int i : list) {System.out.print(i + " ");}}
}

并行归并排序(基于 Fork/Join 框架)与普通方法对比

package com.forkjoin;import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;/*** Fork/Join框架高效地自动执行和协调所有任务* @author Jing61*/
public class ParallelMergeSort {// 5000000条数据public static final int SIZE = 50000000;public static void main(String[] args) {// 用于普通归并排序int[] list1 = new int[SIZE];// 用于并行归并排序int[] list2 = new int[SIZE];for (int i = 0; i < SIZE; i++) list1[i] = list2[i] = (int) (Math.random() * 100000000);// 普通归并排序var begin = System.currentTimeMillis();MergeSort.sort(list1);var end = System.currentTimeMillis();System.out.println("普通(单线程)归并排序耗时:" + (end - begin) + "ms");// 并行归并排序begin = System.currentTimeMillis();sort(list2);end = System.currentTimeMillis();System.out.println("并行归并排序耗时:" + (end - begin) + "ms");}public static void sort(int[] list) {var pool = new ForkJoinPool();pool.invoke(new SortTask(list));}/*** 创建一个任务* RecursiveAction:定义不返回值的任务* RecursiveTask:定义返回值的任务*/public static class SortTask extends RecursiveAction {private static final long serialVersionUID = 1L;private static final int THRESHOLD = 500;private int[] list;public SortTask(int[] list) {this.list = list;}@Overrideprotected void compute() {if (list.length <= THRESHOLD) { // 数据量小于500时,使用普通排序算法Arrays.sort(list);return;} // 递归终止条件int middle = list.length / 2;int[] firstHalf = new int[middle];System.arraycopy(list, 0, firstHalf, 0, firstHalf.length);int[] secondHalf = new int[list.length - middle];System.arraycopy(list, middle, secondHalf, 0, secondHalf.length);// fork/joininvokeAll(new SortTask(firstHalf), new SortTask(secondHalf));// 合并数组MergeSort.merge(firstHalf, secondHalf, list);}}
}

执行结果对比
image

并行排序通过多线程并行处理子任务,耗时显著低于单线程排序。


示例二:线性表查找最大数(有返回值)

普通(单线程)查找方法与并行查找方法对比

package com.forkjoin;import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;/*** @author Jing61*/
public class ParalleMax {private static final int SIZE = 50000000;public static void main(String[] args) {Integer[] list = new Integer[SIZE];for (int i = 0; i < SIZE; i++) list[i] = (int) (Math.random() * 1000000000);// 普通方法获取最大值var begin = System.currentTimeMillis();Integer max = list[0];for (int i = 1; i < SIZE; i++) max = Math.max(list[i], max);var end = System.currentTimeMillis();System.out.println("普通方法获取最大值为:" + max + "耗时:" + (end - begin) + "ms");// 并行方法获取最大值begin = System.currentTimeMillis();max = max(list);end = System.currentTimeMillis();System.out.println("并行方法获取最大值为:" + max + "耗时:" + (end - begin) + "ms");}public static Integer max(Integer[] list) {var pool = new ForkJoinPool();return pool.invoke(new MaxTask(list, 0, list.length - 1));}/*** RecursiveTask:定义返回值的任务* <>里面填写返回值类型*/static class MaxTask extends RecursiveTask<Integer> {private static final long serialVersionUID = 1L;private static final int THRESHOLD = 500;private Integer[] list;private int low;private int high;public MaxTask(Integer[] list, int low, int high) {this.list = list;this.low = low;this.high = high;}@Overrideprotected Integer compute() {// 数组小于等于阈值时,使用普通算法更加高效if(high - low + 1 <= THRESHOLD) {Integer max = list[low];for(int i = low + 1; i <= high; i++) if(list[i] > max) max = list[i];return max;} else {int middle = low + (high - low) / 2;// invokeAll(new MaxTask(list, low, middle), new MaxTask(list, middle + 1, high));var left = new MaxTask(list, low, middle);var right = new MaxTask(list, middle + 1, high);left.fork();right.fork();return Math.max(left.join(), right.join());}}}}

执行结果对比
image

并行查找通过拆分任务并行处理,大幅提升查找效率。


补充说明

  1. 阈值设置原则:阈值过小会导致任务拆分过多,增加线程调度开销;阈值过大则无法充分利用并行优势,需根据任务类型和数据量合理调整。
  2. 适用场景:Fork/Join 框架适合处理可拆分、无依赖的任务,如排序、查找、数据统计等,不适合处理有状态或依赖外部资源的任务。
  3. 性能优势:通过多线程并行利用多核CPU资源,减少整体任务执行时间,数据量越大,并行优势越明显。
http://www.jsqmd.com/news/40386/

相关文章:

  • 视频汇聚平台EasyCVR化解高速服务区管理难题,打造高速服务区的智慧监控方案
  • Linux Shell脚本基础语法
  • 不懂 Attention 不算懂 AI?十大奠基论文(一):一文读懂《Attention Is All You Need》
  • 2025年直埋保温管供货厂家权威推荐榜单:热力管道/夹克保温管/预制直埋保温管源头厂家精选
  • 2025上海专业防水补漏推荐!Top5口碑公司实测,先检测后施工有保障
  • 2025年通风气楼厂家权威推荐榜单:钢结构厂房气楼/顺坡气楼/排烟通风气楼源头厂家精选
  • 楼宇间网络拓扑测绘 从原理到精准部署
  • IP种子技术:构建全球P2P网络实时监测方案
  • IP应用场景全图谱:你的IP属于哪一类?
  • windows下配置cmake+opencv报错
  • 编译lazarus时,可能出现Makefile:3520: recipe for target fcllaz.ppu failed的处理方法
  • 破局代码思维:软件开发公司的体验式竞争力进化
  • IP定位面积揭秘:为什么你的IP归属地会不准确?
  • 无需人工奖励!Meta FAIR华人团队提出「早期经验学习范式」,AI智能体像人类一样“从错误中成长”
  • 嵌入式PWRKEY多功能使用攻略与设计要点探讨!
  • 单调队列优化多重背包
  • 2025年广东儿子不学习沉迷网络公司权威推荐榜单:青少年戒掉网瘾/初中生沉迷网络游戏/孩子沉迷网络游戏源头公司精选
  • 打造景区“视觉中枢”:视频融合平台EasyCVR助力智慧景区安防智能化升级
  • [books]Love, Money, and Parenting: How Economics Explains the Way We Raise Our Kids 5 Febrero 2019
  • 一个小白的YOLOv10(MindYOLO)推理初尝试
  • Proxmox VE创建Linux虚拟机、相关设置分析
  • 2025年AI数字人企业排名大揭秘:前十强出炉,ai排行榜/ai排名/视频矩阵/短视频矩阵/ai和数字人/抖音短视频矩阵/GEO公司口碑推荐
  • 文本生成器(AC自动机上DP)
  • ICLR2026 !SAM3重磅来袭:能“听懂人话”的分割模型,性能狂飙2倍
  • 2025 年升降机械厂家最新推荐榜:液压升降机械,解析供货厂家服务质量与产品性能
  • pandas strftime 时间错误问题
  • 2025年哈尔滨私立高中机构权威推荐榜单:好的私立高中/一对一辅导/河北名师源头机构精选
  • nginx做tcp代理时的超时时间参数设置和解释
  • 【往届会后三个月完成EI检索 | IEEE出版】第二届智能机器人与自动控制国际学术会议(IRAC 2025)
  • 精准把控VBAT,轻松规避电源设计99%陷阱