You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CompletableFuture递归循环未达40000次提前终止问题求助

CompletableFuture递归循环提前终止问题排查与解决

问题代码

private static void loop(Supplier<CompletionStage<Boolean>> body) {
    CompletionStage<Boolean> result = body.get();
    Log.i(TAG, "after get");
    result.whenComplete((r, e) -> {
         if (r) {
            Log.i(TAG, "call loop ");
            loop(body);
        } else {
            Log.i(TAG, "exit loop");
        }
    });
}

int cnt = 0;

void test() {
    CompletableFuture<Void> supervisor = new CompletableFuture<>();
    loop(() -> {
        Log.i(TAG, "cnt=" + cnt);
        if(cnt ++ < 40000)
            return CompletableFuture.completedFuture(true);
        else  {
            return CompletableFuture.completedFuture(false);
        }
    });
    Log.i(TAG, "leave");
}

执行输出

I/MainActivity: cnt=0
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=1
I/MainActivity: after get
I/MainActivity: call loop
...
I/MainActivity: cnt=3073
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=3074
I/MainActivity: after get
I/MainActivity: call loop
I/MainActivity: cnt=3075
I/MainActivity: after get
I/MainActivity: leave

原因分析

核心问题是栈溢出:

  • 代码中CompletableFuture.completedFuture()返回的是已完成的Future,whenComplete的回调会同步执行在当前调用线程中。
  • 每次递归调用loop()都会直接在当前栈帧上压入新的调用栈,随着循环次数增加,调用栈深度不断累积,当达到Android虚拟机的栈容量上限时,会抛出StackOverflowError,导致线程终止,循环提前结束。
  • 由于Android Logcat未捕获该异常,所以表现为循环“提前结束”,实际是线程因栈溢出崩溃。

解决方案

要避免递归栈溢出,需让递归调用不在当前线程栈上同步执行,或改用非递归的链式调用逻辑。

方案1:异步调度递归调用

利用CompletableFuture的异步方法,将回调调度到通用线程池执行,避免栈累积:

private static void loop(Supplier<CompletionStage<Boolean>> body) {
    CompletionStage<Boolean> result = body.get();
    Log.i(TAG, "after get");
    // 使用thenRunAsync异步触发下一次循环,规避栈溢出
    result.thenRunAsync(() -> {
        try {
            boolean r = result.toCompletableFuture().join();
            if (r) {
                Log.i(TAG, "call loop ");
                loop(body);
            } else {
                Log.i(TAG, "exit loop");
            }
        } catch (Exception e) {
            Log.e(TAG, "Loop error", e);
        }
    });
}

方案2:非递归链式调用(更推荐)

完全消除递归逻辑,用循环构建CompletableFuture链式调用,从根源上避免栈溢出:

void test() {
    CompletableFuture<Boolean> currentFuture = CompletableFuture.completedFuture(true);
    while (cnt < 40000) {
        currentFuture = currentFuture.thenApply(r -> {
            if (!r) return false;
            Log.i(TAG, "cnt=" + cnt);
            return cnt++ < 40000;
        });
    }
    currentFuture.thenRun(() -> Log.i(TAG, "exit loop"));
    Log.i(TAG, "leave");
}

内容的提问来源于stack exchange,提问作者lucas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 20:20:55