我们需要在一个分支池中将一个素数计算拆分成多个递归任务。
我们有一个素数列表和一个workloadSize,比如5,所以如果我们想计算50的素因数,我们把所有的素数都设为25,然后计算素因数。workloadSize是单个递归任务将处理的质数的数量。
我做了什么:
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;我是不是完全搞错了?我总是得到一个并发异常和堆栈溢出。我想我没有正确地连接递归任务,因为它总是导致堆栈溢出。
发布于 2019-06-24 21:39:12
完整的堆栈跟踪和更完整的代码示例应该有助于澄清发生了什么。但是,在您所展示的代码中,有几点是很突出的。
调用主任务
在您的示例中,您需要
pool.execute(worker);
resultList = worker.invoke();这不是它应该工作的方式。
调用"execute“会分派任务,这很好,但它不会等待任务完成。因此,您只是启动了一个计算,在其完成或结果时没有句柄。
自己调用invoke不是你通常会做的事情,你应该让pool自己调用这个方法。因为它将在调用线程中启动任务的执行,而不需要任何池的支持。因此,如果你以不合逻辑的顺序执行join,你甚至可能会死锁自己。
调用RecursiveTask<T>的“预定”方式是调用pool.invoke(task),它将返回T (计算结果)或pool.submit(task),后者将返回Future。
在任务之间共享状态
任务中的这段代码可能会有问题:
List<Long> results = calcFactors(...);
results.addAll(f.join);如果calcFactors创建自己的List来返回,它就会起作用。但是,如果这个列表在任务之间共享,这意味着多个任务(和线程)可以在同一实例上执行addAll,这只有在列表能够支持它的情况下才能工作(我认为JDK中唯一并发的List是CopyOnWriteArrayList)。
https://stackoverflow.com/questions/56734350
复制相似问题