2

我的问题可以通过给出一个代码片段来最好地解释:

public static void main(final String[] a) {
    Stream.of(1, 2, 3, 4).map(i -> ForkJoinPool.commonPool().submit(new RecursiveAction() {
        @Override
        protected void compute() {
            System.out.println(Thread.currentThread());
        }
    })).forEach(ForkJoinTask::join);
}

在我有 4 个内核的笔记本电脑上运行它时,会打印:

Thread[main,5,main]
Thread[ForkJoinPool.commonPool-worker-1,5,main]
Thread[main,5,main]
Thread[ForkJoinPool.commonPool-worker-1,5,main]

为什么某些任务跑在主线程中,主线程是普通fork join线程池之外的线程?

创建自定义分叉连接线程池时,不会发生这种情况:

public static void main(final String[] a) {
    final ForkJoinPool p = new ForkJoinPool(4);

    Stream.of(1, 2, 3, 4).map(index -> p.submit(new RecursiveAction() {
        @Override
        protected void compute() {
            System.out.println(Thread.currentThread());
        }
    })).forEach(ForkJoinTask::join);
}

Thread[ForkJoinPool-1-worker-1,5,main]
Thread[ForkJoinPool-1-worker-1,5,main]
Thread[ForkJoinPool-1-worker-1,5,main]
Thread[ForkJoinPool-1-worker-1,5,main]

那么,换句话说,普通池有什么特别之处呢?有了这些知识,在公共池中执行长时间运行的任务是明智的还是不明智的想法?

4

2 回答 2

5

发生了一些相当聪明的事情。

当您ForkJoinTask::join从不在线程中的线程调用时ForkJoinPool.awaitJoin,当前线程可以“帮助”任务执行(来自注释)。

所以这就是主线程在 fork-join 池中执行任务的原因。

但是,为什么在您创建自定义池的情况下会有所不同?好吧,我的猜测是您的自定义池有足够的线程,不需要主线程。因为另一件事是,默认情况下,“公共池”的创建线程少于可用处理器的数量。


有关更多详细信息,请查看源代码。请注意,此行为未在 javadocs 中指定,因此它可能会在未来的实现中更改。

于 2017-08-26T07:19:21.830 回答
3

阐述我的其他评论:

使用提交线程作为工作线程一直与性能有关。在工作窃取优先程序中,提交线程将新请求放入提交队列并通知工作线程有工作。(确切地,哪些线程得到通知已随时间而变化。)

工作窃取线程只能通过从其他线程的双端队列窃取或进入提交队列来获得工作。(由于只使用一个的扩展问题,现在有多个提交队列。)线程如何找到工作是无关紧要的。相关的是它很慢。线程需要唤醒并去寻找工作。由于线程的队列是双端队列,因此无法将工作分配给任何线程。这个设计的主要原因是作者抄袭了 Cilk 的设计。

Cilk 是集群 fork/join 程序。它主要工作在计算机连接网络的集群环境中。有一个工作共享算法,其中计算机查询其他计算机的队列以查看哪里有工作,或者,将分叉的任务放在哪里(放入队列中用于负载平衡的挂起任务数量最少的队列)是令人望而却步的。因此,在集群环境中,使用 deques 优先工作窃取是可取的。

在 Java 中,环境是共享内存。在其他线程的队列中查找的开销很小。在任何情况下,对框架的第一个请求都需要从线程中唤醒、寻找工作,而且速度很慢。

对于 Java8 并行流,系统需要公共池和加速处理的方法。(并行线程的初始时间很糟糕。)因此,作者提出了将提交线程用作工作线程的想法。然而,这种技术引入了它自己的问题,正如这里提到的:http: //coopsoft.com/ar/Calamity2Article.html#submission

于 2017-08-27T14:32:54.383 回答