java Fork/Join 关于堆栈用法的说明

2022-09-02 22:23:56

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

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

据我所知,JVM不支持尾部调用优化(在这种情况下可能会删除连接方法堆栈帧),我相信在执行具有大量分叉和连接的复杂操作时,线程可能会抛出一个.StackOverflowError

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

编辑

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

正如你所看到的,分叉连接框架被转换为普通递归。因为java不支持尾部调用优化 - Java中的每个递归都可能导致如果它足够深入。StackOverflowError

我的问题是 - 分叉/连接框架的实现者是否找到了一些很酷的方法来防止这种情况。


答案 1

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

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


答案 2

通常,在堆栈上推送的每个新任务的大小都是前一个任务的一半。因此,工作量随着堆栈大小呈指数级增长。即使有一个小堆栈,你也将能够适应足够多的工作,让你忙碌一段时间。


推荐