Java并发基础:CompletableFuture全面解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: CompletableFuture类使得并发任务的处理变得简单而高效,通过简洁的API,开发者能轻松创建、组合和链式调用异步操作,无需关心底层线程管理,这不仅提升了程序的响应速度,还优化了资源利用率,让复杂的并发逻辑变得易于掌控。

Java并发基础:CompletableFuture全面解析 - 程序员古德

内容概要

CompletableFuture类使得并发任务的处理变得简单而高效,通过简洁的API,开发者能轻松创建、组合和链式调用异步操作,无需关心底层线程管理,这不仅提升了程序的响应速度,还优化了资源利用率,让复杂的并发逻辑变得易于掌控。

核心概念

CompletableFuture 是一个非常强大的并发工具类,它实现了 FutureCompletionStage 接口,用于表示某个异步计算的结果,与传统的 Future 不同,CompletableFuture 提供了函数式编程的方法,可以更容易地组织异步代码,处理回调和组合多个异步操作。

假设,有一个电商网站,用户浏览产品详情页时,需要展示产品的基本信息、价格、库存、用户评价等多个方面的数据,这些数据可能来自不同的数据源或服务,比如:

  1. 产品基本信息可能来自一个主数据库。
  2. 价格库存 可能需要实时从另一个库存服务获取。
  3. 用户评价可能存储在另一个专门用于用户反馈的系统中。

为了提升用户体验,希望这些数据的获取能够并行进行,而不是一个接一个地串行获取,这就是 CompletableFuture 的经典场景。

CompletableFuture 类在主要用来解决异步编程和并发执行的问题,在传统的同步编程模型中,代码的执行通常是阻塞的,即一行代码执行完成后,下一行代码才能开始执行,这种模型在处理耗时操作时,如 I/O 操作、数据库访问或网络请求,会导致线程长时间闲置,等待操作完成,从而降低系统的吞吐量和响应能力。

因此,CompletableFuture 类提供了一种非阻塞的、基于回调的编程方式,可以在等待某个长时间运行的任务完成时,同时执行其他任务,这样,就可以更充分地利用系统资源,提高程序的并发性和响应速度。

使用CompletableFuture通常用于解决以下类似场景的问题:

  1. 发起异步请求:当用户请求一个产品详情页时,后端服务可以同时发起对三个数据源的异步请求,这可以通过创建三个 CompletableFuture 实例来实现,每个实例负责一个数据源的请求。
  2. 处理异步结果:一旦这些异步请求发出,它们就可以独立地执行,主线程可以继续处理其他任务,当某个 CompletableFuture 完成时,它会包含一个结果(或者是执行过程中的异常)。
  3. 组合异步结果:使用 CompletableFuture 的组合方法(如 thenCombinethenAcceptBothallOf),可以等待所有异步操作完成,并将它们的结果组合在一起,比如,可以等待产品基本信息、价格和库存以及用户评价都返回后,再将这些数据整合到一个响应对象中,返回给前端。
  4. 异常处理:如果在获取某个数据源时发生异常,CompletableFuture 允许以异步的方式处理这些异常,比如通过 exceptionally 方法提供一个默认的备选结果或执行一些清理操作。
  5. 最终响应:一旦所有数据源的数据都成功获取并组合在一起,或者某个数据源发生异常并得到了妥善处理,服务就可以将最终的产品详情页响应发送给前端用户。

使用CompletableFuture 可以高效的并发数据获取,提升系统的响应速度和整体性能。

代码案例

当然,以下是一个简单的Java代码示例,演示了如何使用CompletableFuture类来异步执行任务,并在任务完成后获取结果,这个示例模拟了一个client调用,异步地获取两个不同数据源的数据,并在它们都完成后组合这两个结果,如下代码案例:

import java.util.concurrent.CompletableFuture;  
import java.util.concurrent.ExecutionException;  

public class CompletableFutureDemo {
   
     

    // 模拟从某个数据源获取数据的耗时操作  
    private static String fetchDataFromSourceA() {
   
     
        simulateSlowService();  
        return "Data from Source A";  
    }  

    // 模拟从另一个数据源获取数据的耗时操作  
    private static String fetchDataFromSourceB() {
   
     
        simulateSlowService();  
        return "Data from Source B";  
    }  

    // 模拟耗时操作的方法(例如网络延迟)  
    private static void simulateSlowService() {
   
     
        try {
   
     
            Thread.sleep(2000); // 模拟耗时2秒  
        } catch (InterruptedException e) {
   
     
            e.printStackTrace();  
        }  
    }  

    // 客户端调用示例  
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
     
        // 创建两个异步任务  
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(CompletableFutureDemo::fetchDataFromSourceA);  
        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(CompletableFutureDemo::fetchDataFromSourceB);  

        // 当两个任务都完成时,组合它们的结果  
        CompletableFuture<String> combinedFuture = futureA.thenCombine(futureB, (resultA, resultB) -> {
   
     
            return resultA + " and " + resultB;  
        });  

        // 等待组合任务完成并获取结果  
        String combinedResult = combinedFuture.get();  

        // 输出结果  
        System.out.println("Combined result: " + combinedResult);  
    }  
}
AI 代码解读

在上面代码中:

fetchDataFromSourceAfetchDataFromSourceB 方法模拟了从两个不同的数据源获取数据的耗时操作,simulateSlowService 方法通过让当前线程休眠2秒来模拟一个耗时操作,在 main 方法中,使用 CompletableFuture.supplyAsync 方法创建了两个异步任务,分别对应两个数据源的数据获取,使用 thenCombine 方法将这两个异步任务的结果组合在一起,当两个任务都完成时,会调用提供的 lambda 表达式来合并结果,combinedFuture.get() 方法会阻塞当前线程,直到组合任务完成并返回结果。

核心API

CompletableFuture 列用于表示某个异步计算的结果,它提供了函数式编程的方法来处理异步计算,允许以非阻塞的方式编写并发代码,并且可以链接多个异步操作,以下是一些常用方法的含义:

1、静态工厂方法

  • CompletableFuture.supplyAsync(Supplier<? extends U> supplier): 异步执行给定的 Supplier,并返回一个表示结果的新 CompletableFuture
  • CompletableFuture.supplyAsync(Supplier<? extends U> supplier, Executor executor): 使用指定的执行器异步执行给定的 Supplier
  • CompletableFuture.runAsync(Runnable runnable): 异步执行给定的 Runnable,并返回一个表示其完成的新 CompletableFuture
  • CompletableFuture.runAsync(Runnable runnable, Executor executor): 使用指定的执行器异步执行给定的 Runnable

2、完成时的处理

  • thenApply(Function<? super T,? extends U> fn): 当此 CompletableFuture 完成时,对其结果应用给定的函数。
  • thenAccept(Consumer<? super T> action): 当此 CompletableFuture 完成时,执行给定的操作。
  • thenRun(Runnable action): 当此 CompletableFuture 完成时,执行给定的无参数操作。

3、异常处理

  • exceptionally(Function<Throwable,? extends T> fn): 当此 CompletableFuture 异常完成时,对其异常应用给定的函数。

4、组合多个 CompletableFuture

  • thenCombine(CompletableFuture<? extends U> other, BiFunction<? super T,? super U,? extends V> fn): 当此 CompletableFuture 和另一个都完成时,使用给定的函数组合它们的结果。
  • thenAcceptBoth(CompletableFuture<? extends U> other, BiConsumer<? super T,? super U> action): 当此 CompletableFuture 和另一个都完成时,对它们的结果执行给定的操作。
  • runAfterBoth(CompletableFuture<?> other, Runnable action): 当此 CompletableFuture 和另一个都完成时,执行给定的操作。
  • applyToEither(CompletableFuture<? extends T> other, Function<? super T, U> fn): 当此 CompletableFuture 或另一个完成时(哪个先完成),对其结果应用给定的函数。
  • acceptEither(CompletableFuture<? extends T> other, Consumer<? super T> action): 当此 CompletableFuture 或另一个完成时(哪个先完成),对其结果执行给定的操作。
  • runAfterEither(CompletableFuture<?> other, Runnable action): 当此 CompletableFuture 或另一个完成时(哪个先完成),执行给定的操作。

5、等待和获取结果

  • get(): 等待计算完成,然后获取其结果。
  • get(long timeout, TimeUnit unit): 等待计算在给定的时间内完成,并获取其结果。
  • join(): 类似于 get(),但是会在计算未完成时抛出未检查的异常。
  • complete(T value): 如果尚未完成,则设置此 CompletableFuture 的结果。
  • completeExceptionally(Throwable ex): 如果尚未完成,则使此 CompletableFuture 异常完成。

6、取消

  • cancel(boolean mayInterruptIfRunning): 尝试取消此 CompletableFuture
  • isCancelled(): 如果此 CompletableFuture 被取消,则返回 true

7、查询

  • isDone(): 如果此 CompletableFuture 完成(无论是正常完成还是异常完成),则返回 true

核心总结

Java并发基础:CompletableFuture全面解析 - 程序员古德

CompletableFuture类为异步编程提供了强大的支持,使得并发处理变得更加直观和高效,它能够轻松创建、组合和管理异步任务,提升程序的响应性和吞吐量,但是如果遇到错误处理相对复杂,可能需要额外的代码来确保异常被正确处理。对于复杂的异步逻辑,可以尝试将其拆分成小的、易于管理的部分,每个部分使用CompletableFuture来处理,同时,要注意异常处理和资源管理,避免潜在的内存泄漏和程序崩溃。

关注我,每天学习互联网编程技术 - 程序员古德

END!
END!
END!

往期回顾

精品文章

Java并发基础:ConcurrentSkipListMap全面解析

Java并发基础:ConcurrentSkipListSet全面解析!

Java并发基础:SynchronousQueue全面解析!

Java并发基础:ConcurrentLinkedQueue全面解析!

Java并发基础:Exchanger全面解析!

精彩视频

目录
打赏
0
1
1
1
37
分享
相关文章
Java二维数组的使用技巧与实例解析
本文详细介绍了Java中二维数组的使用方法
47 15
Java中Log级别和解析
日志级别定义了日志信息的重要程度,从低到高依次为:TRACE(详细调试)、DEBUG(开发调试)、INFO(一般信息)、WARN(潜在问题)、ERROR(错误信息)和FATAL(严重错误)。开发人员可根据需要设置不同的日志级别,以控制日志输出量,避免影响性能或干扰问题排查。日志框架如Log4j 2由Logger、Appender和Layout组成,通过配置文件指定日志级别、输出目标和格式。
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
65 6
【潜意识Java】期末考试可能考的高质量大题及答案解析
Java 期末考试大题整理:设计一个学生信息管理系统,涵盖面向对象编程、集合类、文件操作、异常处理和多线程等知识点。系统功能包括添加、查询、删除、显示所有学生信息、按成绩排序及文件存储。通过本题,考生可以巩固 Java 基础知识并掌握综合应用技能。代码解析详细,适合复习备考。
22 4
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
135 2
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
100 1
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
86 0
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等