gpt4 book ai didi

java-8 - ForkJoinPool#awaitQuiescence 实际上是如何工作的?

转载 作者:行者123 更新时间:2023-12-04 16:25:04 24 4
gpt4 key购买 nike

我有 RecursiveAction 的下一个实现,这个类的唯一目的是从 0 打印到 9,但如果可能的话,从不同的线程打印:

public class MyRecursiveAction extends RecursiveAction {
private final int num;

public MyRecursiveAction(int num) {
this.num = num;
}

@Override
protected void compute() {
if (num < 10) {
System.out.println(num);
new MyRecursiveAction(num + 1).fork();
}
}
}

我认为调用 awaitQuiescence 将使当前线程等待,直到所有任务(提交和 fork )都将完成:

public class Main {
public static void main(String[] args) {
ForkJoinPool forkJoinPool = new ForkJoinPool();
forkJoinPool.execute(new MyRecursiveAction(0));
System.out.println(forkJoinPool.awaitQuiescence(5, TimeUnit.SECONDS) ? "tasks" : "time");
}
}

但我并不总是得到正确的结果,而不是打印 10 次,而是打印 0 到 10 次。

但如果我将 helpQuiesce 添加到 RecursiveAction 的实现中:

public class MyRecursiveAction extends RecursiveAction {
private final int num;

public MyRecursiveAction(int num) {
this.num = num;
}

@Override
protected void compute() {
if (num < 10) {
System.out.println(num);
new MyRecursiveAction(num + 1).fork();
}

RecursiveAction.helpQuiesce();//here
}
}

一切正常。

我想知道 awaitQuiescence 究竟在等待什么?

最佳答案

当您将 System.out.println(num); 更改为 System.out.println(num + ""+ Thread.currentThread() 时,您会知道会发生什么);

这可能会打印如下内容:

0 Thread[ForkJoinPool-1-worker-3,5,main]
1 Thread[main,5,main]
tasks
2 Thread[ForkJoinPool.commonPool-worker-3,5,main]

awaitQuiescence 检测到有待处理的任务时,它会通过窃取一个并直接执行它来提供帮助。 Its documentation说:

If called by a ForkJoinTask operating in this pool, equivalent in effect to ForkJoinTask.helpQuiesce(). Otherwise, waits and/or attempts to assist performing tasks until this pool isQuiescent() or the indicated timeout elapses.

我添加的重点

这发生在这里,正如我们所见,一个任务打印“main”作为它的执行线程。然后,fork() 的行为被指定为:

Arranges to asynchronously execute this task in the pool the current task is running in, if applicable, or using the ForkJoinPool.commonPool() if not inForkJoinPool().

由于main线程不是ForkJoinPool的工作线程,fork()会将新任务提交给commonPool()。从那时起,从公共(public)池的工作线程调用的 fork() 也将提交下一个任务到公共(public)池。但是在自定义池上调用的 awaitQuiescence 不会等待公共(public)池的任务完成,并且 JVM 过早终止。

如果你要说这是一个有缺陷的 API 设计,我不会反对。

解决方案是不要将 awaitQuiescence 用于除公共(public)池¹之外的任何内容。通常,拆分子任务的 RecursiveAction 应该等待它们完成。然后,您可以等待根任务完成,等待所有关联任务完成。

this answer的后半部分包含这样一个 RecursiveAction 实现的示例。

¹ awaitQuiescence 在您没有实际操作的情况下很有用,例如提交到公共(public)池的并行流。

关于java-8 - ForkJoinPool#awaitQuiescence 实际上是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66643737/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com