java fork /Join 关于堆栈使用情况的说明

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

我阅读了Java 7中引入的Fork / Join框架的实现,我只是想检查一下我是否理解这个魔法是如何工作的。

据我所知,当线程分叉时,它会在其队列中创建子任务(其他线程可能会或可能不会窃取)。当线程尝试“加入”时,它实际上会检查队列中是否存在任务,然后递归执行它们,这意味着对于任何“加入”操作,将在线程调用堆栈中添加2个帧(一个用于加入和一个为新的任务调用)。

因为我知道JVM不支持尾部调用优化(可能会在这种情况下删除连接方法堆栈帧),我相信在执行复杂的操作时会出现很多分支和连接,因此线程可能会抛出一个StackOverflowError

我是对的还是他们找到一些很酷的方法来阻止它?

下面是一个有助于澄清问题的场景:假设(为了简单起见)我们在forkjoin池中只有一个线程。在某个时间点 - 线程分叉,然后调用加入。在join方法中,线程发现它可以执行分叉的任务(就像它在队列中发现的那样),因此它会调用下一个任务。这个任务依次派生,然后调用连接 - 所以在执行连接方法时,线程会在其队列中找到派生的任务(像以前一样)并调用它。在那个阶段,调用堆栈将至少包含两个连接和两个任务的帧。

正如你所看到的fork连接框架转换为纯递归。由于java不支持尾部调用优化 - StackOverflowError如果深度足够,java中的每个递归都可能导致。

我的问题是 - fork / join框架的实现者是否找到了防止这种情况的很酷的方法。

提问于
用户回答回答于

不幸的是,在线程递归栈方面没有任何神奇的事情发生。如果您的初始任务分叉/分裂并且没有合理的分辨率点,那么您将遇到StackOverflowErrors。

你也许可以理解为什么JavaDoc上的教程将每个子任务分成两半。

用户回答回答于

通常,每个推送到堆栈上的新任务都是前一个任务的一半。所以工作量随着堆栈大小呈指数级增长。即使只有一小堆,你仍然可以适应绰绰有余的工作,以保持你一段时间的忙碌。

扫码关注云+社区