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

Java CompletableFuture行为解析:异步任务无输出问题排查

你的猜想完全正确!

你猜的没错——当注释掉cf.join()时,主线程会在CompletableFuture的异步任务完成前就终止了。核心原因是:CompletableFuture.supplyAsync()和thenAcceptAsync()默认使用**ForkJoinPool.commonPool()**中的守护线程,JVM不会等待守护线程执行完成,只要所有非守护线程(比如主线程)结束,JVM就会直接退出,导致异步打印任务还没来得及执行就被终止了。

而启用cf.join()时,这个方法会阻塞主线程,直到异步任务全部完成。你看到两次打印的原因是:

  • thenAcceptAsync()会在异步线程中打印一次结果
  • 如果同时执行System.out.println(cf.join()),主线程又会获取结果再打印一次,自然就重复了。

解决方法

这里有几种实用的解决方案,你可以根据场景选择:

1. 用join()等待任务完成,避免重复打印

如果想保留异步打印的逻辑,只需要用join()阻塞主线程等待任务结束,不要额外打印结果即可:

public class Main { 
    public static String getJSON(String u) { 
        if (u == null) throw new IllegalArgumentException("URL is null."); 
        try { 
            URL url = new URL(u); 
            URLConnection site = url.openConnection(); 
            InputStream is = site.getInputStream(); 
            Scanner scanner = new Scanner(new BufferedInputStream(is), "UTF-8"); 
            String resp = ""; 
            while (scanner.hasNextLine()) { 
                resp += scanner.nextLine(); 
            } 
            return resp; 
        } catch (Exception e) { 
            System.out.println(e); 
            return null; 
        } 
    } 

    public static void main(String[] args) { 
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(
            () -> getJSON("https://jsonplaceholder.typicode.com/posts/1")
        ); 
        
        // 异步打印结果
        cf.thenAcceptAsync(System.out::println); 
        
        // 阻塞主线程,等待所有异步任务完成
        cf.join(); 
    } 
}

2. 直接用join()获取结果并打印(简化逻辑)

如果不需要异步打印的场景,直接在主线程获取结果打印会更简洁:

public static void main(String[] args) { 
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(
        () -> getJSON("https://jsonplaceholder.typicode.com/posts/1")
    ); 
    
    // 等待结果并打印,无需额外异步任务
    System.out.println(cf.join()); 
}

3. 使用CountDownLatch(多任务场景更灵活)

如果你的程序存在多个异步任务需要等待,CountDownLatch会是更合适的选择:

import java.util.concurrent.CountDownLatch;

public class Main { 
    public static String getJSON(String u) { 
        // 原方法逻辑不变
    } 

    public static void main(String[] args) throws InterruptedException { 
        CountDownLatch latch = new CountDownLatch(1);
        
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(
            () -> getJSON("https://jsonplaceholder.typicode.com/posts/1")
        ); 
        
        cf.thenAcceptAsync(resp -> {
            System.out.println(resp);
            // 任务完成后计数减一
            latch.countDown();
        }); 
        
        // 主线程等待,直到计数变为0
        latch.await();
    } 
}

内容的提问来源于stack exchange,提问作者Mohideen Imran Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:07:01