ForkJoinTask 必须提交到 ForkJoinPool 才能并行执行,直接 new 后调用 compute() 是同步串行;应按需选用 RecursiveTask(有返回值)或 RecursiveAction(无返回值);fork() 与 join() 需逻辑配对,推荐 left.fork(); right.compute(); left.join() 模式;自定义 ForkJoinPool 应显式设置 parallelism,避免使用 commonPool 处理 IO 密集型任务。

ForkJoinTask 不是拿来直接 new 的,得用 ForkJoinPool 调度才能真正并行执行。
为什么直接 new ForkJoinTask 不会并行
因为 ForkJoinTask 本身只是个抽象任务容器,没有线程、没有调度逻辑。它必须提交到 ForkJoinPool(或通过 invoke()/fork() 触发池内线程执行),否则调用 compute() 就是普通同步方法调用,和单线程没区别。
-
ForkJoinPool.commonPool()是默认共享池,适合轻量、短时任务;生产环境建议显式创建带命名和参数的池 - 手动 new
RecursiveAction或RecursiveTask后,必须调用pool.invoke(task)或task.fork().join()才进工作窃取队列 - 忘记调用
fork()而直接写compute()—— 这是最常见的“以为并行实则串行”陷阱
RecursiveTask vs RecursiveAction 怎么选
看任务要不要返回结果:RecursiveTask 有返回值,RecursiveAction 没有。选错会导致编译失败或运行时类型异常。
- 需要聚合子结果(比如归并排序求和、树节点统计)→ 用
RecursiveTask等具体类型 - 只做副作用操作(比如批量更新对象字段、写文件)→ 用
RecursiveAction,避免无意义的null返回 - 注意
RecursiveTask的compute()必须 return 一个值,漏写 return 会编译报错
fork() 和 join() 的配对不是强制语法,但逻辑必须对称
fork() 把子任务提交到当前线程的工作队列尾部,join() 阻塞等待完成并获取结果。二者不一定要紧邻,但顺序和数量要匹配,否则可能死锁或漏等。
请注意以下说明:1、本程序允许任何人免费使用。2、本程序采用PHP+MYSQL架构编写。并且经过ZEND加密,所以运行环境需要有ZEND引擎支持。3、需要售后服务的,请与本作者联系,联系方式见下方。4、本程序还可以与您的网站想整合,可以实现用户在线服务功能,可以让客户管理自己的信息,可以查询自己的订单状况。以及返点信息等相关客户利益的信息。这个功能可提高客户的向心度。安装方法:1、解压本系统,放在
立即学习“Java免费学习笔记(深入)”;
- 常见错误:只
fork()不join()→ 主任务提前返回,子任务还在后台跑(甚至被丢弃) - 另一个错误:先
join()再fork()→ 实际变成串行,因为join()会阻塞直到前一个fork()的任务结束 - 推荐模式:
left.fork(); right.compute(); left.join();(让右子任务在当前线程算,左子任务异步算,提升局部性)
ForkJoinPool 的 parallelism 参数容易被忽略
默认 commonPool() 的并行度是 Runtime.getRuntime().availableProcessors() - 1,不是 CPU 核数。自定义池若不设 parallelism,可能比预期少一个线程。
- IO 密集型任务不适合 ForkJoinPool,它假设任务是 CPU-bound 的;混入阻塞操作(如
Thread.sleep()、数据库查询)会导致线程饥饿 - 池大小设太大(比如 100)不会提升性能,反而增加任务调度开销和内存占用
- 调试时加
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "2")可控复现竞争逻辑
真正难的不是写 compute(),而是判断任务是否可分、分到多细才划算,以及如何避免共享状态竞争——这些没法靠框架自动解决。









