繁体   English   中英

java Fork / Join有关堆栈使用情况的说明

[英]java Fork/Join clarification about stack usage

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

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

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

我是对的还是他们找到了一些防止它的好方法?

编辑

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

正如您所看到的,fork join框架转换为普通递归。 因为java不支持尾调用优化 - 如果它足够深入,java中的每个递归都会导致StackOverflowError

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

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

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

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

我希望我能以正确的方式理解你。

forkjoinpool中有内部队列来保存您要执行的任务,因此不会抛出堆栈溢出,但您必须为高内存利用率做好准备。

fork方法非常有趣的地方是ForkJoinWorkerThread.pushTask,使用不安全的对象,所以你应该注意数组用于存储任务。

编辑:首先和简单 - 当你在队列的顶部时,你只需要按下并执行,然后返回retult。 (forkjointask.java:353)

当你有依赖关系时使用不同的方法,在这种情况下,控制返回到WorkerThread,然后负责检测链并执行它们。 第一个工作人员检查本地队列是否有任何未完成的任务,如果没有这样的任务,它执行传递的作业并返回结果,否则进入下一个案例。 这几次帮助了偷窃者。 没有什么可以帮助......第一步的重试等于MAX_HELP现在为零 - 控制被传递给池,它执行多次检查并执行tryAwaitDone。 在这种方法中,调用wait来等待任务完成。

这意味着fork join pool将分几步完成,尝试通过避免等待调用来优化速度和时间。 然而,它可以等待完成,然后这将意味着启动同步过程非常昂贵。

因此,对于无限深度没有后续连接,但是尽可能快地执行任务的逻辑尝试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM