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

时间:2015-05-14 16:31:49

标签: java multithreading fork-join

我们说我们扩展了一个名为RecursiveTask的{​​{1}}。

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

MyRecursiveTask

我认为" t2"将位于Workqueue的顶部(这是一个deque,它被用作worker本身的堆栈),因为我看到了fork方法的实现,如下所示:

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

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

表达式1:

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;
}

表达式2:

t1.join() + t2.join()

我认为这可能很重要。在t2.join() + t1.join() 完成之前,t1.join()将始终阻塞(如果没有工作窃取),因为只有workQueue顶部的任务才能被激活。 (换句话说,t2必须在t1加速之前加速)。以下是t2.join()doJoin的代码。

tryUnpush

有没有人有这方面的想法?谢谢!

2 个答案:

答案 0 :(得分:5)

您使用Java7还是Java8很重要。在Java7中,框架为join()创建了延续线程。在Java8中,框架主要用于join()。 See here. 自2010年以来,我一直在撰写关于此框架的评论。

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

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

这样分裂线程就会继续操作。

由于此代码经常更改,因此不建议依赖F / J代码进行指导。例如,在Java8中使用嵌套并行流导致过多的补偿线程,代码在Java8u40中重新编写只会导致更多问题。 See here

如果你必须进行多次连接,那么加入()的顺序并不重要。每个fork()都可以为任何线程提供任务。

答案 1 :(得分:0)

如果你有足够的核心数量而不是两个并行运行的线程,那么首先启动哪一个并不重要,因为完成时间很重要。因此,无论哪一个完成,第一个必须等​​待另一个完成并计算结果。如果你有1个核心而不是你认为可能是真的,但对于1个核心你为什么需要并行化这个工作呢?