Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么fork-join任务在公共fork-join池线程之外执行?_Java_Java.util.concurrent_Fork Join_Forkjoinpool - Fatal编程技术网

Java 为什么fork-join任务在公共fork-join池线程之外执行?

Java 为什么fork-join任务在公共fork-join池线程之外执行?,java,java.util.concurrent,fork-join,forkjoinpool,Java,Java.util.concurrent,Fork Join,Forkjoinpool,我的问题最好通过给出一段代码片段来解释: 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

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

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线程池之外的线程

创建自定义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]

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

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

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

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

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



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

要详细说明我的其他评论:

使用提交线程作为工作线程一直与性能有关。在抢工第一个程序中,提交线程将新请求放入提交队列,并通知工作线程有工作。(确切地说,得到通知的线程已随时间而更改。)

工作窃取线程只能通过从其他线程的任务中窃取或转到提交队列来获取工作。(由于只使用一个提交队列的伸缩问题,现在有多个提交队列。)线程如何找到工作与此无关。相关的是它的速度很慢。线程需要醒来并去寻找工作。由于线程的队列是deques,因此无法将工作分配给任何线程。这个设计的主要原因是作者从Cilk复制了这个设计

Cilk是集群fork/join程序。它主要在计算机通过网络连接的集群环境中工作。禁止使用工作共享算法,其中计算机查询其他计算机的队列以查看哪里有工作,或者将分叉的任务放在哪里(放入具有最少数量待处理任务的队列以实现负载平衡)。因此,在集群环境中,优先使用deques

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


对于Java8并行流,系统需要公共池和一种加速流程的方法。(并行线程的初始计时非常糟糕。)因此,作者提出了将提交线程用作辅助线程的想法。然而,正如这里所提到的,这种技术本身也带来了一些问题:

在接受错误的答案之前,你应该等到得到几个答案。@edharned请随意创建一个新的答案,并提供更多的见解!我很想听到更多。接受的答案总是可以更改的,所以没有问题。为什么将提交线程用作工作线程并不聪明?提交线程必须按照
join()
等待。所以它可以等待什么也不做,或者它也可以尽最大努力提前完成工作?我不明白?