【问题标题】:Collecting List<Long> results from RecursiveTask of a ForkJoinPool从 ForkJoinPool 的 RecursiveTask 收集 List<Long> 结果
【发布时间】:2019-06-24 10:11:09
【问题描述】:

我们需要在一个 forkjoinpool 中将一个素数计算拆分为多个递归任务。

我们有一个质数列表和一个工作负载大小,比如 5。 因此,如果我们要计算 50 的质因数,我们将所有质数都设为 25 并计算质因数。工作负载大小是单个递归任务将处理的素数数量。

我做了什么:

Long[] workLoad = new Long[primes.size()];
workLoad = primes.toArray(workLoad);

pool = new ForkJoinPool();
ForkJoinWorker worker = new ForkJoinWorker(workLoad, q, partitionSize, 0);
pool.execute(worker);

resultList =  worker.invoke();

workLoad = 所有素数的数组。

q = 我们要计算质因数的数。

ForkJoinWorker 扩展了一个 RecursiveTask>

在递归任务中,我查看 workLoadSize 是否大于我得到的素数数组,如果是,我创建一个新的

ForkJoinWorker f = new ForkJoinWorker(..);
f.fork();
List<Long> results = calcFactors(...);
results.addAll(f.join);
return results;

我是不是完全搞错了?我总是遇到并发异常和堆栈溢出。我认为我没有正确连接递归任务,因为它总是会导致堆栈溢出。

【问题讨论】:

    标签: java recursion primes fork-join


    【解决方案1】:

    完整的堆栈跟踪和更完整的代码示例应该有助于阐明发生了什么。但是您显示的代码中有几件事很突出。

    调用主任务

    在你的样本中,你做

    pool.execute(worker);
    resultList =  worker.invoke();
    

    这不是它应该工作的方式。

    调用“execute”会分派任务,这很好,但它不会等待它完成。所以你刚刚启动了一个计算,它的完成或结果没有句柄。

    你自己调用invoke不是你通常会做的事情,你应该让pool自己调用这个方法。因为它将在调用线程中开始执行任务,没有任何池的支持。所以如果你join的顺序不合逻辑,你甚至可能会陷入僵局。

    调用RecursiveTask&lt;T&gt; 的“预期”方式是调用pool.invoke(task),这将返回一个T(计算结果)或pool.submit(task),它将返回一个Future .

    任务间共享状态

    任务中的这段代码可能有问题:

    List<Long> results = calcFactors(...);
    results.addAll(f.join);
    

    如果calcFactors 创建自己的List 来返回,它将起作用。但是如果这个列表是在任务之间共享的,这意味着多个任务(和线程)可能在同一个实例上执行addAll,这只有在列表能够支持的情况下才会起作用(我认为唯一并发的List在JDK 是CopyOnWriteArrayList)。

    【讨论】:

      猜你喜欢
      • 2019-07-21
      • 1970-01-01
      • 2012-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多