Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.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体系结构扩展时的StackOverflower错误_Java_Algorithm_Fork Join - Fatal编程技术网

Java 使用fork/join体系结构扩展时的StackOverflower错误

Java 使用fork/join体系结构扩展时的StackOverflower错误,java,algorithm,fork-join,Java,Algorithm,Fork Join,我试图用经典的斐波那契算法学习递归任务类。该算法工作正常,直到斐波那契数超过17000,然后抛出StackOverflower错误。我不知道问题是线程的数量还是我使用缓存来存储计算出的数量。我知道有更好的算法来计算斐波那契数,但这只是为了了解fork/join结构及其局限性。较低的数字(例如数字17800)所需的时间为153毫秒,缓存大小为13 MB 问题:如何使用相同的算法使此代码更好地扩展(计算更高的数字) 斐波那契码: public class FibonacciTask extends

我试图用经典的斐波那契算法学习递归任务类。该算法工作正常,直到斐波那契数超过17000,然后抛出StackOverflower错误。我不知道问题是线程的数量还是我使用缓存来存储计算出的数量。我知道有更好的算法来计算斐波那契数,但这只是为了了解fork/join结构及其局限性。较低的数字(例如数字17800)所需的时间为153毫秒,缓存大小为13 MB

问题:如何使用相同的算法使此代码更好地扩展(计算更高的数字)

斐波那契码:

public class FibonacciTask extends RecursiveTask<BigInteger>{
    // this theshold is used because the overhead of the architecture
    // makes the process crazy slow if we try to use it on easy problems
    private static final int EASYCALC = 10; 
    // limit of the cache
    private static final int CACHELIM = 20000; 
    private int n;

    private static Map<Integer, BigInteger> fibCache = new ConcurrentHashMap<>();

    public BigInteger result;

    public FibonacciTask(int x, Map<Integer, BigInteger> fibCache){
        n = x;
        this.fibCache = fibCache;

        // calculate the first 10 numbers without threads
        if(!fibCache.containsKey(EASYCALC)){

            fibCache.put(EASYCALC, this.fibonacci(EASYCALC));
            result = fibCache.get(x);
        }
    }

    @Override
    protected BigInteger compute() {
        if(!fibCache.containsKey(n)){

            FibonacciTask worker1 = new FibonacciTask(n-1, fibCache);
            FibonacciTask worker2 = new FibonacciTask(n-2, fibCache);
            worker1.fork(); // fork this work to new thread

            result = worker2.compute().add(worker1.join());

            if(n >= CACHELIM){
                return result;
            }
            fibCache.put(n, result);
        }
        return fibCache.get(n);
    }
    // calculate without threads
    public BigInteger fibonacci(int n){

        if(!fibCache.containsKey(n) ){
            fibCache.put(n, fibonacci(n-1).add(fibonacci(n-2)) );
        }

        return fibCache.get(n);
    }    
}
错误输出:

run:
No. of processors: 8
Exception in thread "main" java.lang.StackOverflowError
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:536)
    at java.util.concurrent.ForkJoinTask.reportResult(ForkJoinTask.java:596)
    at java.util.concurrent.ForkJoinTask.join(ForkJoinTask.java:640)
    at java.util.concurrent.ForkJoinPool.invoke(ForkJoinPool.java:1521)
    at cachedThreadedFibonacci.SmartWorker.main(SmartWorker.java:62)
Caused by: java.lang.StackOverflowError
    at cachedThreadedFibonacci.FibonacciTask.compute(FibonacciTask.java:48)
    at cachedThreadedFibonacci.FibonacciTask.compute(FibonacciTask.java:55)
    at cachedThreadedFibonacci.FibonacciTask.compute(FibonacciTask.java:55)
    ... same line repeating 
编辑 我还感到困惑,因为如果我在Netbeans中将堆栈大小设置为2Mb(-Xss2M),那么它就可以正常工作(即使在我的测试中缓存可以达到17Mb)?如果我将大小设置为1 Mb,它将不再工作(在前面描述的同一点失败),我缺少什么?

以下(不完整)片段来自您的
FibonacciTask

@Override
protected BigInteger compute() {
    if(!fibCache.containsKey(n)){

        FibonacciTask worker1 = new FibonacciTask(n-1, fibCache);
        FibonacciTask worker2 = new FibonacciTask(n-2, fibCache);
        worker1.fork(); // fork this work to new thread

        result = worker2.compute().add(worker1.join());

     // ... snip ...
}
您的问题过于关注fork-join池使用的线程数量。虽然调用
worker1.fork()
会在不同的线程上产生工作,但这不是问题的根源。对
worker2.compute()
的调用发生在当前线程上,即使该方法在不同(新)实例上被调用。每次这样的调用都会创建自己的
worker2
实例,并在同一线程上继续调用该对象的
compute()
方法

这是一个递归算法,更不用说任务扩展了。每个线程有有限的内存可用于维护方法调用堆栈。任何足够深的递归算法都可以超过这个极限;正如您所观察到的,在Java中,这会导致一个
StackOverflowException

试图将此错误与基于地图的缓存的大小联系起来是毫无意义的。映射及其内容位于堆上,堆是与线程调用堆栈完全分离的内存区域

FibonacciTask task = new FibonacciTask(n, fibCache);
pool.invoke(task);

这会导致对由
pool.invoke()
选择的单线程上的
compute()
进行至少(n/2)次调用的堆栈深度,该调用用于执行任务的第一次迭代。如果
n
的值足够大,则可以超过允许的最大堆栈深度。正如您所发现的,对于给定的
n
,可以防止此错误。但是,对于这样的递归算法,增加堆栈大小并不能“修复”问题,它只是延迟问题,直到您为
n
选择一个新值,该值足够高,足以超过新的每线程堆栈内存区域。

在哪个级别引发异常?在“result=worker2.compute()”行引发异常。添加(worker1.join())。我希望这能回答问题。好吧,你在使用递归,所以很明显你很容易受到堆栈溢出的影响。惊喜在哪里?我希望有某种方法可以控制排队来解决这个问题的线程数。因为即使我不使用递归,问题也可能会发生,然后就更难确定和解决了解决它。所以这只是为了学习如何在没有意外崩溃的情况下创建安全的应用程序……如果一个线程的堆栈超过了允许的最大大小,那么线程的数量又有什么关系呢?
FibonacciTask task = new FibonacciTask(n, fibCache);
pool.invoke(task);