当前位置: 首页 > news >正文

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 密集型计算

http://www.dtcms.com/a/109720.html

相关文章:

  • 面向对象软件开发与中国哲学的关系
  • Java面试题及答案整理( 2025年 4 月最新版,持续更新)
  • 每天10分钟!自动抓取并生成每日简报的AI方案
  • 从零开始训练Codebook:基于ViT的图像重建实践
  • 认识 Promise
  • 三、GPIO
  • 【上新了】深入理解 Java 虚拟线程:与传统线程的对比及应用
  • Vue2 监听器 watcher
  • qt tcpsocket编程遇到的并发问题
  • Spring Boot应用中实现Jar包热更新的实践指南
  • macOS设置定时播放眼保健操
  • Java的数据库编程——JDBC基础
  • 2025年AI技术十大趋势深度解析:从实验室到主流应用
  • 移动端六大语言速记:第6部分 - 错误处理与调试
  • CAS:47623-98-3,DiSBAC2(3)一种慢反应的膜电位敏感探针
  • 进程和内存管理
  • 浅谈Tomcat数据源连接池
  • sql server数据库可疑修复
  • 提取嘉立创3D封装
  • 递归典例---汉诺塔
  • java 并发编程-阻塞队列
  • 升级到oracle 19.8后vm_concat函数不可用怎么解决
  • 网络空间安全(51)邮件函数漏洞
  • DeepSeek技术原理解读:从算法革新到产业变革
  • 【大模型基础_毛玉仁】6.4 生成增强
  • 【Spring AOP】@Aspect、 @Pointcut使用@annotation + 五种通知Advice注解
  • AI爬虫?爬!
  • Python入门(7):模块
  • 事件处理程序
  • 主题(topic)中使用键(key)来区分同一主题下的多个数据实例