介绍:
递归,就是自己调用自己,比如:
int foo(int n) {
if (n == 1) {
return 1;
}
return foo(n - 1) + 1;
}
问题
- 每调用一次方法, 就会在当前线程的虚拟机栈中分配一块内存空间,称为栈帧。
- 递归调用时,次数越多,入栈的栈帧越多,最终导致栈溢出(StackOverflowError)。
static int deep;
public void stackTest() {
deep++;
stackTest();
}
public static void main(String[] args) {
StackOverflowTest test = new StackOverflowTest();
try {
test.stackTest();
} catch (Throwable e) {
System.out.println(e.toString());
System.out.println(deep);
}
}
方案1:
递归一定深度后直接返回结果,由外部变量保存,接着继续递归
public class Test {
public static void main(String[] args) {
int result = 0;
Test test = new Test();
do {
result = test.foo(result, 0);
} while (!test.isEnd(result));
System.out.println("程序运行结束 --- result = " + result);
}
private int maxDeep = 1000;
private int foo(int count, int deep) {
if (isEnd(count)) {
return count;
}
if (deep >= maxDeep) {
System.out.println(Thread.currentThread().getName() + " --- " + count);
return count;
}
count++;
deep++;
return foo(count, deep);
}
public boolean isEnd(int count) {
return count >= 1000000;
}
}
方案2:
因为虚拟机栈是线程私有的,递归一定次数后,后续的递归调用让新线程来处理,减轻栈内存压力
public class Test {
public static void main(String[] args) throws InterruptedException, ExecutionException {
int result = 0;
// 线程池复用
ExecutorService executorService = Executors.newSingleThreadExecutor();
do {
result = executorService.submit(new MyTask(result)).get();
} while (!MyTask.isEnd(result));
executorService.shutdown();
System.out.println("程序运行结束 --- result = " + result);
}
}
public class MyTask implements Callable<Integer> {
public MyTask(int count) {
this.count = count;
}
private int count;
private int maxDeep = 1000;
private int deep = 0;
@Override
public Integer call() throws Exception {
return foo(count);
}
private int foo(int count) {
if (isEnd(count)) {
return count;
}
if (deep >= maxDeep) {
System.out.println(Thread.currentThread().getName() + " --- " + count);
return count;
}
count++;
deep++;
return foo(count);
}
public static boolean isEnd(int count) {
return count >= 1000000;
}
}