Java中的可变深度递归

Java中的可变深度递归,java,eclipse,concurrency,recursion,Java,Eclipse,Concurrency,Recursion,因此,我正在做一个小实验,看看递归在Java语言中到底能走多远,因为我要上一堂并发课程,学习Java的线程机制。现在我运行的是一个Intel i5四核,2.8 GHz,4GB内存。我在Windows7上运行x64,在Eclipse上运行标准JRE?我不确定最后一部分我刚从Sun的网站下载了一些东西 反正 public class StacksizeTest implements Runnable { int depth = 0; public void run() { try

因此,我正在做一个小实验,看看递归在Java语言中到底能走多远,因为我要上一堂并发课程,学习Java的线程机制。现在我运行的是一个Intel i5四核,2.8 GHz,4GB内存。我在Windows7上运行x64,在Eclipse上运行标准JRE?我不确定最后一部分我刚从Sun的网站下载了一些东西

反正

public class StacksizeTest implements Runnable {

int depth = 0;

public void run()
{
    try
    {
        doOverflow();
    }
    catch (StackOverflowError e)
    {
        System.out.print("Overflow ocurred at depth " + depth + ".\n");
    }
}

void doOverflow()
{
    depth += 1;
    doOverflow();
}

public static void main(String argv[])
{
    Thread mt = new Thread(new StacksizeTest());
    mt.start();
    mt.run();
}   
}
我还使用默认的调用堆栈大小运行,根据设置文件,我很确定它是512Mb

因此,当我运行程序并启动一个新线程时,我会不断获得不同的深度,以及打印语句打印两次。我认为print语句是有意义的,因为它应该在一个新线程上运行mt。我所困惑的是,如果我排除.start并调用.run,深度总是相同的,大约11500左右,但当我使用.start时,深度是可变的。一对夫妇分别是22789、22330和22381。我很难理解为什么会这样。有人能解释一下这个问题吗

谢谢

Matt

对.start的调用将使用run启动一个新线程,然后您将在主线程上再次调用run。因此,有两个堆栈深度线程同时运行。由于您还拥有一个共享变量来计算不受同步互斥保护的深度,因此存在一个典型的变量争用问题

为了避免将问题与变量争用混淆,我将自己限制为一个正在运行的堆栈深度检查器实例。

调用.start将使用run启动一个新线程,然后在主线程上再次调用run。因此,有两个堆栈深度线程同时运行。由于您还拥有一个共享变量来计算不受同步互斥保护的深度,因此存在一个典型的变量争用问题

为了避免将问题与变量争用混淆,我将自己限制为一个正在运行的堆栈深度检查器实例。

当您调用start时,您将异步启动该方法,因此您将运行它两次,因为start最终会调用run,此外,您还将自己调用run,所以有两个线程在增加深度计数器。取消启动,您将获得较小的计数,因为您只运行一个线程

编辑:我刚看到格雷格的答案。我更喜欢他的方法。

当你调用start时,你是在异步启动这个方法,所以你要运行两次,因为start最终会调用run,另外你自己调用run,所以你有两个线程在增加深度计数器。取消启动,您将获得较小的计数,因为您只运行一个线程


编辑:我刚看到格雷格的答案。我更喜欢他。

哦,你是说两个线程都在调用深度变量,这是两个线程执行的粗略相加?没错。这不是一个合适的添加,因为您有线程争用:线程1读取深度、线程2读取深度、1添加1、2添加1、1存储深度、2存储深度。这段代码本来打算在深度上增加两个,但第二个存储深度覆盖了第一个存储深度的效果,最后只增加了一个。不完全是这样。没有同步,所以一切都是可能的。每个线程可能会在寄存器中保留自己的深度版本,因此最终可能会有两个独立变量。或者,它们可能很好,并且处理一个公共变量。其中一个线程可能比另一个线程运行得更快。基本上,最终得到的是完全无用的数字,介于N和2*N之间,其中N是通过使用单个线程获得的结果。继续,当我达到注释长度限制时,编译器也可以选择进行优化,因此将递归转化为迭代,这样就不会再有不想要的堆栈溢出双关语。好了,当前的JIT不能这样做。哦,你是说两个线程都在调用深度变量,这是两个线程执行的粗略相加?没错。这不是一个合适的添加,因为您有线程争用:线程1读取深度、线程2读取深度、1添加1、2添加1、1存储深度、2存储深度。这段代码本来打算在深度上增加两个,但第二个存储深度覆盖了第一个存储深度的效果,最后只增加了一个。不完全是这样。没有同步,所以一切都是可能的。每个线程可能会在寄存器中保留自己的深度版本,因此最终可能会有两个独立变量。或者,它们可能很好,并且处理一个公共变量。其中一个线程可能比另一个线程运行得更快。基本上,最终得到的是完全无用的数字,介于N和2*N之间,其中N是通过使用单个线程获得的结果。继续当我达到注释长度限制时,编译器也可以选择进行优化,因此将递归转化为迭代,因此 o更多的堆栈溢出双关语不是有意的。抱歉,当前的JIT无法实现这一点。