0

0

在Java里ForkJoin框架如何工作_Java任务拆分并行机制说明

P粉602998670

P粉602998670

发布时间:2026-01-14 15:14:48

|

502人浏览过

|

来源于php中文网

原创

forkjoinpool线程数应按任务类型选择:纯计算型用默认值(cpu核数-1),混合型可设为cpu核数×2;recursivetask自动合并返回值,recursiveaction无结果合并,适合副作用操作;阈值需权衡并行开销与cpu利用率,建议从array.length/(parallelism×4)起步实测;阻塞操作必须移出compute()或用managedblock()包装,否则导致线程饥饿。

在java里forkjoin框架如何工作_java任务拆分并行机制说明

ForkJoinPool 怎么选线程数才不拖慢任务

ForkJoinPool 默认并行度是 Runtime.getRuntime().availableProcessors() - 1(注意不是全部核数),这是为避免工作线程和后台 GC 线程争抢 CPU。如果你的任务大量阻塞(比如 IO),默认配置反而会让线程闲置、吞吐下降。

  • 纯计算型任务:保持默认即可,改大可能引发上下文切换开销
  • 混合型任务(含短 IO 或 sleep):可显式构造 ForkJoinPool(int parallelism),设为 availableProcessors() * 2 左右观察效果
  • 全局替换默认池(不推荐):用 ForkJoinPool.commonPool().shutdown() + 自定义池接管,但会影响所有用 commonPool() 的第三方库

RecursiveTask 和 RecursiveAction 的核心区别在哪

区别不在“能不能返回值”,而在于框架如何调度和合并结果——RecursiveTaskinvoke()join() 会等待子任务完成并自动获取 compute() 返回值;RecursiveActioncompute() 返回 void,没有结果合并逻辑,适合副作用操作(如批量写文件、更新数组某段)。

  • 误用 RecursiveAction 去做需要累加的归并(如求和),就得自己维护共享变量,容易出竞态
  • RecursiveTask 却忽略返回值或没在 compute() 里 return,会导致父任务拿到 null 或默认值,运行时可能 NPE
  • 子任务调用 fork() 后,必须用 join() 获取结果(RecursiveTask)或确保执行完成(RecursiveAction),只 fork()join() 是常见漏写点

任务拆分阈值(threshold)设多少才算合理

阈值不是越大越好,也不是越小越好。它本质是「串行执行 vs. 并行开销」的平衡点。拆太细,任务创建、队列入、线程唤醒的开销会盖过计算收益;拆太粗,并行度上不去,CPU 利用率低。

  • 简单规则:对数组处理类任务,阈值常设为 array.length / (parallelism * 4) 左右起步(例如 100 万元素、8 核机器,初试 3 万)
  • System.nanoTime() 对比不同阈值下总耗时,重点关注 5~10 次运行的中位数,避开 GC 毛刺干扰
  • 避免用固定数字如 101000 —— 这在小数据集上可能触发过度拆分,在大数据集上又形同单线程

常见阻塞操作为什么会让 ForkJoinPool 卡住

ForkJoinPool 的工作线程是**守护线程**,且默认不允许阻塞。一旦在 compute() 里调用 Thread.sleep()Object.wait()、数据库查询、Socket 读写等,该线程就挂起,无法窃取其他任务,整个池可能因线程耗尽而停滞。

VIVA
VIVA

一个免费的AI创意视觉设计平台

下载

立即学习Java免费学习笔记(深入)”;

  • 正确做法:把阻塞操作移出 compute(),改用 CompletableFuture.supplyAsync(..., yourExecutor) 配合自定义线程池处理
  • 不得已要阻塞?先调用 ForkJoinPool.managedBlock(new ManagedBlocker() {...}) 告知框架“我要停一下”,否则可能触发 RejectionException
  • 日志里看到 Attempt to invoke fork() from non-FJ thread 或大量 helpQuiesce() 调用,基本就是阻塞导致线程饥饿了
public class SumTask extends RecursiveTask<Long> {
    private final int[] array;
    private final int lo, hi;
    private static final int THRESHOLD = 10_000; // 实际应按数据量动态算
<pre class='brush:java;toolbar:false;'>SumTask(int[] array, int lo, int hi) {
    this.array = array;
    this.lo = lo;
    this.hi = hi;
}

@Override
protected Long compute() {
    if (hi - lo <= THRESHOLD) {
        long sum = 0;
        for (int i = lo; i < hi; i++) sum += array[i];
        return sum;
    }
    int mid = (lo + hi) >> 1;
    SumTask left = new SumTask(array, lo, mid);
    SumTask right = new SumTask(array, mid, hi);
    left.fork(); // 异步提交左子任务
    long rightResult = right.compute(); // 当前线程算右半边(避免额外线程开销)
    long leftResult = left.join();      // 等待左半边结果
    return leftResult + rightResult;
}

}

ForkJoin 的难点不在 API 调用,而在判断「哪里该切」「切多细」「哪些操作根本不能放进去」——这些没法靠文档背出来,得结合数据规模、硬件特征和实际 profile 结果反复调。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1089

2024.03.01

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1010

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

611

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

334

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

134

2025.11.27

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.3万人学习

C# 教程
C# 教程

共94课时 | 11.1万人学习

Java 教程
Java 教程

共578课时 | 80.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号