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
相关产品推荐
相关产品推荐

