CompletableFuture:核心方法、应用场景

1. 引言

在现代 Java 开发中,异步编程是提升应用性能的重要手段。CompletableFuture 作为 Java 8 引入的异步编程工具,不仅提供了丰富的 API 用于任务管理,还能让代码更加优雅地处理并发逻辑。

本文将深入解析 CompletableFuture 的常见方法,结合实际代码示例,并统计任务执行耗时,帮助你更好地理解 CompletableFuture 在实际开发中的应用场景。

2. CompletableFuture 常见方法及应用场景

2.1 supplyAsync() & runAsync() —— 创建异步任务

  • supplyAsync(Supplier):有返回值
  • runAsync(Runnable):无返回值
  • 适用场景远程 API 调用、数据库查询、文件 IO
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    try { Thread.sleep(1000); } catch (InterruptedException e) { }
    return "Hello, CompletableFuture!";
});
System.out.println(future.get()); // 阻塞等待执行结果

2.2 thenApply() —— 任务结果转换

  • 适用场景:对异步任务的结果进行后续计算
Instant start = Instant.now();

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { }
    return 10;
}).thenApply(result -> result * 2); //将 result*2

System.out.println("cost: " + Duration.between(start, Instant.now()).toSeconds() + "s , result is " + future.get());

2.3 thenCompose() —— 连接两个异步任务

  • **适用场景:**第一个任务的结果作为第二个异步任务的输入
static void testThenCompose() throws ExecutionException, InterruptedException {
    Instant start = Instant.now();

    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { }
        return 10;
    }).thenCompose(result -> CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { }
        return result * 2;
    }));

    System.out.println("cost: " + Duration.between(start, Instant.now()).toSeconds() + "s , result is " + future.get());
}
  • 执行结果分析: f1(2s)+f2(3s) ≈ 5s

2.4 thenCombine() —— 合并两个异步任务的结果

  • 适用场景:合并数据库查询、合并 API 请求数据
static void testThenCombine() throws ExecutionException, InterruptedException {
    Instant start = Instant.now();

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(7); } catch (InterruptedException e) { }
        return 10;
    });
    CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(13); } catch (InterruptedException e) { }
        return 20;
    });

    CompletableFuture<Integer> combinedFuture = future1.thenCombine(future2, Integer::sum);
    System.out.println("cost: " + Duration.between(start, Instant.now()).toSeconds() + "s , result is " + combinedFuture.get());
}
  • 执行结果分析:
    • future1 运行 7s,future2 运行 13s
    • thenCombine() 需要等待两个任务都完成,所以总时间 ≈ 13s

2.5 allOf() —— 等待所有任务完成

  • 适用场景:多个 API 并行请求,全部完成后执行逻辑
static void testAllOf() throws ExecutionException, InterruptedException {
    Instant start = Instant.now();

    CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { }
        return 10;
    });
    CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { }
        return 20;
    });
    CompletableFuture<Integer> f3 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { }
        return 30;
    });

    CompletableFuture<Void> allFutures = CompletableFuture.allOf(f1, f2, f3);
    allFutures.join(); // 等待所有任务完成

    int sum = f1.get() + f2.get() + f3.get();
    System.out.println("cost: " + Duration.between(start, Instant.now()).toSeconds() + "s , result is " + sum);
}
  • 执行结果分析: f1(3s),f2(5s),f3(2s),allOf() 取最大时间 ≈ 5s

2.6 anyOf() —— 等待最快的任务完成

  • 适用场景:多个数据源查询,获取最快的结果
static void testAnyOf() throws ExecutionException, InterruptedException {
    Instant start = Instant.now();

    CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { }
        return "Task 1";
    });
    CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> {
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { }
        return "Task 2";
    });

    CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2);
    System.out.println("cost: " + Duration.between(start, Instant.now()).toSeconds() + "s , result is " + any.get());
}

-执行结果分析: f1(5s),f2(3s),返回最快的 ≈ 3s

2.7 exceptionally() —— 处理异常

  • 适用场景:网络请求失败时提供默认值
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
    if (true) throw new RuntimeException("任务失败!");
    return 10;
}).exceptionally(ex -> {
    System.out.println("发生异常:" + ex.getMessage());
    return -1;
});
System.out.println(future.get());

3. 总结

方法作用适用场景
supplyAsync()创建异步任务(有返回值)API 调用、数据库查询
thenApply()转换任务结果计算返回值
thenCompose()连接两个异步任务任务依赖执行
thenCombine()合并两个任务的结果订单计算、价格合并
exceptionally()处理异常任务失败回退
allOf()等待所有任务完成并行任务
anyOf()只要有一个完成即返回竞态任务

4.其它

4.1指定线程池

在 CompletableFuture 中,supplyAsync() 方法默认使用ForkJoinPool.commonPool() 线程池执行任务。但如果需要使用自定义线程池,可以传递 Executor 作为参数,例如 Executors.newFixedThreadPool()
示例:使用自定义线程池

import java.util.concurrent.*;

public class CompletableFutureWithCustomThreadPool {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService customThreadPool = Executors.newFixedThreadPool(5);

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("Running in thread: " + Thread.currentThread().getName());
            return 42;
        }, customThreadPool);

        System.out.println("Result: " + future.get());

        customThreadPool.shutdown(); // 记得关闭线程池
    }
}

执行结果

Running in thread: pool-1-thread-1
Result: 42

此示例使用了 固定大小的线程池,确保 CompletableFuture 任务在特定的线程池中执行,而不会与默认的 ForkJoinPool 共享资源。

适用场景
• 限制并发线程数,避免 ForkJoinPool 线程数失控
• 需要隔离 CompletableFuture 任务与其他任务(如 Web 服务器主线程)
• 适用于 数据库查询、API 调用、CPU 密集型计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值