fork / join多线程?

时间:2012-07-06 21:00:10

标签: java fork-join

如果我有2个CPU并为fork / join框架安排1000个任务,那么一次最多可以执行2个任务,还是在同一个CPU上并行执行更多任务? (比方说,也许有一个任务正在等待I / O,在这种情况下CPU将变为空闲而另一个线程可以运行)

5 个答案:

答案 0 :(得分:5)

如果您自己不包含任何限制,则不会应用任何限制,Java将尽可能多地分叉线程(可能全部为1000,具体取决于系统限制)。这不太理想。如果你正在进行的计算可能有一些IO时间,但即使在大量的并发处理中也不会受到IO约束,你可能能够证明运行多一个线程,然后再运行可用的CPU数量。一次全部运行1000并不明智。

  

如果我有两个CPU并为fork / join框架安排1000个任务,那么一次最多可以执行2个任务,还是在同一个CPU上并行执行更多任务?< / p>

如果您有双核CPU,则一次只能实际执行2个线程。

答案 1 :(得分:3)

根据the ForkJoin documentation

  

使用给定的目标并行度级构建ForkJoinPool;    默认情况下,等于可用处理器数量 。池尝试维护足够的活动(或可用)线程   动态添加,挂起或恢复内部工作线程,   即使某些任务停滞等待加入他人。但是,没有   面对被阻止的IO或其他,这种调整是有保证的   非托管同步。

所以它可能会在你的2个CPU上一次运行两个,如果CPU是超线程的话,可能一次运行四个(我不确定)。如果您对默认的并行级别不满意,可以通过调用以并行级别作为参数的ForkJoinPool构造函数来指定请求的并行级别。

答案 2 :(得分:1)

是否在cpu上启用了超线程?如果是这样,您可以同时运行2个以上的流程。

  

超线程的工作方式是复制处理器的某些部分 - 存储架构状态的部分 - 但不复制主要执行资源。这允许超线程处理器作为主机操作系统的两个“逻辑”处理器出现,允许操作系统同时调度两个线程或进程。

答案 3 :(得分:0)

我做了一个测试来验证这一点:

import java.util.concurrent.*;

public class Test {
    private static class TestAction extends RecursiveAction {
        private int i;

        public TestAction(int i) {
            this.i = i;
        }

        protected void compute() {
            if (i == 0) {
                invokeAll(new TestAction(1), new TestAction(2), new TestAction(3),
                          new TestAction(4), new TestAction(5), new TestAction(6));
                return;   
            }             
            System.out.println(i + " start");
            try { Thread.sleep(2000); } catch (Exception e) { }
            System.out.println(i + " end"); 
        }   
    }       

    public static void main(String[] args) {
        new ForkJoinPool().invoke(new TestAction(0));
    }   
}       

使用参考Oracle实现运行的结果是:

1 start
6 start <- wait 2 seconds
1 end
2 start
6 end
5 start <- wait 2 seconds
2 end
3 start
5 end
4 start <- wait 2 seconds
4 end
3 end

在Linux和Mac OS X上,相同的行为是一致的。

所以问题的答案是:是的,任务将在parallelism参数指定的CPU数量(或默认的总可用CPU)上执行。如果CPU时间可用且任务只是阻止等待某事,那么框架将不会自动执行任何其他任务。

由于我到目前为止看到的文档非常模糊,如果CPU是空闲的,框架应该做什么,这可能是一个实现细节。

答案 4 :(得分:0)

默认情况下,Fork / Join Framework会尝试将线程数保持等于核心数量(如果是单个核心机器,则创建一个线程)。您可以在makeCommonPool类中的ForkJoinPool方法中查看此代码。

如果您认为这会对您的CPU利用不足,则可以为parallelism提供自定义值。

但最有趣的是,当当前线程占用IO上的CPU块时,有一种方法可以使ForkJoinPool创建更多线程。您所需要做的就是实现代码块,该代码块实际上阻塞了block对象的ForkJoinPool.ManagedBlocker方法实现中的IO,并将该ManagedBlocker对象传递给{{1 } managedBlock类的方法。完成此操作后,ForkJoinPool将检查调用此方法的当前线程是否为ForkJoinPool的实例。如果是,则ForkJoinPoolWorkerThread通过创建可以接管CPU的新线程来补偿。

ForkjoinPool