当前位置: 首页 > 知识库问答 >
问题:

在Java的ForkJoinTask中,fork/join的顺序重要吗?

诸新霁
2023-03-14

假设我们扩展了一个名为<code>MyRecursiveTask。

然后在 forkJoinTask 的范围内创建两个子任务:

MyRecursiveTask t1 = new MyRecursiveTask()
MyRecursiveTask t2 = new MyRecursiveTask()
t1.fork()
t2.fork()

我认为“t2”将位于工作队列的顶部(这是一个deque,它被用作worker本身的堆栈),因为我看到fork方法的实现如下:

public final ForkJoinTask<V> fork() {
    Thread t;
    if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
        ((ForkJoinWorkerThread)t).workQueue.push(this);
    else
        ForkJoinPool.common.externalPush(this);
    return this;
}

如果是,以下两个表达式的性能是否存在差异:

表达式1:

t1.join() + t2.join()

表达式 2:

t2.join() + t1.join()

我认为这可能很重要t1.join()在<code>t2.join()完成之前将始终处于阻塞状态(如果没有工作窃取),因为只有工作队列顶部的任务才能被弹出。(换句话说,t2必须在t1被弹出之前被弹出)。下面是<code>doJoin

private int doJoin() {
    int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
    return (s = status) < 0 ? s :
        ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
        (w = (wt = (ForkJoinWorkerThread)t).workQueue).
        tryUnpush(this) && (s = doExec()) < 0 ? s :
        wt.pool.awaitJoin(w, this, 0L) :
        externalAwaitDone();
}

/**
 * Pops the given task only if it is at the current top.
 * (A shared version is available only via FJP.tryExternalUnpush)
*/
final boolean tryUnpush(ForkJoinTask<?> t) {
    ForkJoinTask<?>[] a; int s;
    if ((a = array) != null && (s = top) != base &&
        U.compareAndSwapObject
        (a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
        U.putOrderedInt(this, QTOP, s);
        return true;
    }
    return false;
}

有人对此有想法吗?谢谢

共有2个答案

葛哲彦
2023-03-14

如果有足够的内核数,那么两个线程并行运行,先启动哪一个并不重要,因为竞争时间很重要。因此,无论谁先完成,都必须等待另一个完成并计算结果。如果您只有一个内核,那么您的想法可能是正确的,但是对于一个内核,您为什么需要并行化作业呢?

龙志勇
2023-03-14

无论您使用Java7还是Java8都很重要。在Java7中,框架为join()创建延续线程。在Java8中,框架主要为join()暂停。请参阅此处。自2010年以来,我一直在写一篇关于这个框架的评论。

使用RecursiveTask的建议(来自JavaDoc):

return f2.compute() + f1.join();

这样,拆分线程将继续操作本身。

不推荐依靠F/J代码来指引方向,因为这种代码经常变化。例如,在Java8中使用嵌套的并行流导致了太多的补偿线程,以至于在Java8u40中重新编写了代码,结果导致了更多的问题。看这里。

如果必须执行多个连接,那么连接()的顺序实际上并不重要。每个fork()使任务可用于任何线程。

 类似资料:
  • fork-join框架允许在几个worker上中断某个任务,然后等待结果将它们组合起来。 它在很大程度上利用了多处理器机器的容量。 以下是fork-join框架中使用的核心概念和对象。 Fork Fork是一个过程,在这个过程中,任务将自身分成较小且独立的子任务,这些子任务可以同时执行。 语法 (Syntax) Sum left = new Sum(array, low, mid); left.

  • 本文向大家介绍Java Fork/Join框架,包括了Java Fork/Join框架的使用技巧和注意事项,需要的朋友参考一下 Fork/Join框架是ExecutorService接口的一个实现,通过它我们可以实现多进程。Fork/Join可以用来将一个大任务递归的拆分为多个小任务,目标是充分利用所有的资源尽可能增强应用的性能。 和任何ExecutorService接口的实现一样,Fork/Jo

  • 问题内容: 从MySQL表中选择列时,与列在表中的顺序相比,选择列的顺序是否会影响性能(不考虑可能覆盖列的索引)? 例如,您有一个表,其中包含uid,name,bday行,并具有以下查询。 MySQL是否会以不同的方式看到以下查询,从而导致性能下降? 问题答案: 实际上,顺序并不重要,因此您可以随意随意订购。 编辑:我想更多的背景是有帮助的:据我所知,优化任何查询的过程发生在确切确定要提取行数据的

  • 我已经搜索了网上的各种文章和堆栈溢出问题,但我不能找到这个完美的答案。有许多问题与此相近,但略有不同。 我们知道Java8Streams API在内部使用Fork-Join池。 现在我的问题是如何使用Fork-Join池来划分流管道中的任务? 假设我们有以下内容: null

  • 问题内容: 无论性能如何,我从下面的查询A和B中都能得到相同的结果吗?C和D呢? 问题答案: 对于联接,不,顺序无关紧要。该查询将返回相同的结果,只要你改变你的选择来。 对于(,或)连接,是的,顺序是有意义的-和( 更新 )事情要复杂得多。 首先,外部联接不是可交换的,因此与 外部联接也不是关联的,因此在您的示例中同时涉及(可交换性和关联性)两个属性: 等效于 : 但: 不等同于 : 另一个(希望

  • 问题内容: 我们在Java中使用了三种不同的多线程技术 -Fork / Join pool,Executor Service和CountDownLatch 叉子/加入池 (http://www.javacodegeeks.com/2011/02/java-forkjoin-parallel- programming.html ) Fork / Join框架旨在使分治算法易于并行化。这种类型的算法非