You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于ForkJoinPool中RecursiveAction compute方法与self fork的疑问

ForkJoinPool 相关问题解答

问题一:无join、无终止条件时,fork为何不会无限运行?

你贴的代码里任务并没有无限运行,核心原因在于两点:

  1. invoke()的等待逻辑
    ForkJoinPool.invoke()只负责等待你提交的初始任务完成——也就是初始Test任务的compute()方法执行完毕就返回。你的初始任务compute()里,打印线程名、fork新任务后方法就结束了,所以invoke()很快返回,main线程随之走到程序末尾。

  2. 工作线程是守护线程
    ForkJoinPool的工作线程默认是守护线程,JVM退出的条件是不存在非守护线程。当main线程结束后,JVM会直接终止,不管守护线程上的任务有没有执行完。那些fork出去的新任务可能还在队列里排队,或者刚执行了几步,就被JVM强制终止了,所以每次运行打印的线程名数量都不一样。

如果想要验证任务可以无限生成,只需在main方法末尾加一行Thread.sleep(Long.MAX_VALUE)让main线程一直存活,你会看到任务会不断fork新实例,线程数达到ForkJoinPool的并行度上限(默认是CPU核心数)后,持续运行直到内存耗尽。

问题二:compute中调用自身fork的两种情况

情况一:仅调用fork()

@Override
protected void compute() {
      System.out.println(1);
      fork();
}

表现:compute()被调用1次或2次。

原因:
初始任务的compute()执行时,打印1、fork自身任务后就结束了,invoke()返回,main线程终止JVM。如果fork出去的子任务在JVM退出前被工作线程抢到执行,就会打印第二次1;如果还没来得及执行,就只会打印1次,所以结果不确定。

情况二:调用fork()后再调用join()

@Override
protected void compute() {
      System.out.println(1);
      fork();
      join();
}

表现:compute()被调用多次后停止。

原因:
当任务调用join()时,当前工作线程不会单纯阻塞等待,而是会主动去执行队列中的任务(包括刚fork的子任务)。这样就形成了递归执行链:线程执行任务A → fork任务B → join任务B,线程转而执行任务B → fork任务C → join任务C,线程继续执行任务C……这个过程会一直持续,直到调用栈达到JVM的栈深度上限,抛出StackOverflowError,程序随之终止。


内容的提问来源于stack exchange,提问作者man

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:08:32