Java并发基础:CompletableFuture全面解析

news2024/11/25 12:55:39

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);  
    }  
}

在上面代码中:

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全面解析!

精彩视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1457167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis】 如何保证数据不丢失?

目录 1.Redis 持久化 1.1 RDB 持久化 1.2 AOF 持久化 1.3 混合持久化 2.Redis 集群 2.1 主从同步 2.2 哨兵模式 2.3 Redis Cluster 小结 1.Redis 持久化 持久化是指将数据从内存中存储到持久化存储介质中&#xff08;如硬盘&#xff09;的过程&#xff0c;以便在程序重…

C++之Easyx——图形库的基本准备工作

什么是Easyx&#xff1f; EasyX Graphics Library 是针对 Visual C 的免费绘图库&#xff0c;支持 VC6.0 ~ VC2022&#xff0c;简单易用&#xff0c;学习成本极低&#xff0c;应用领域广泛。目前已有许多大学将 EasyX 应用在教学当中。 它比Red PandaDev C上的图形库功能要强…

好用的UI自动化测试平台推荐

随着软件行业的不断发展&#xff0c;建立一个完善的自动化测试体系变得至关重要。目前&#xff0c;自动化测试主要涵盖接口自动化测试和UI自动化测试两个主要领域。就目前而言&#xff0c;企业在UI自动化测试方面的覆盖率仍然相对较低。 接口自动化测试可以模拟和执行应用程序…

怎么清理mac系统缓存系统垃圾文件 ?怎么清理mac系统DNS缓存

很多使用苹果电脑的用户都喜欢在同时运行多个软件&#xff0c;不过这样会导致在运行一些大型软件的时候出现不必要的卡顿现象&#xff0c;这时候我们就可以去清理下内存&#xff0c;不过很多人可能并不知道正确的清内存方式&#xff0c;下面就和小编一起来看看吧。 mac系统是一…

虚拟机--pc端和macOS端互通

windows开启虚拟化 要在Windows系统中开启虚拟化&#xff0c;您可以按照以下步骤操作&#xff1a; 准备工作&#xff1a; 确保您的计算机CPU支持虚拟化技术。在BIOS中开启相应的虚拟化支持。 开启虚拟化&#xff1a; 打开控制面板&#xff0c;点击程序或功能项&am…

初识KMP算法

目录 1.KMP算法的介绍 2.next数组 3.总结 1.KMP算法的介绍 首先我们会疑惑&#xff0c;什么是KMP算法&#xff1f;这个算法是用来干什么的&#xff1f; KMP&#xff08;Knuth-Morris-Pratt&#xff09;算法是一种用于字符串匹配的经典算法&#xff0c;它的目标是在一个主文本…

Allegro172版本如何用自带功能改变过孔网络属性操作指导

Allegro172版本如何用自带功能改变过孔网络属性操作指导 在用Allegro做PCB设计的时候,时常会需要将过孔的网络进行变更,可以将原来的过孔删除,再重新打一个,这种方法难免会繁琐一些。 当然我们可以借助skill工具来完成更换过孔网络的更改,除此之外,Allegro自带的功能完成…

Excel常用快捷键(持续更新)

引言 excel是我们办公中经常使用的工具&#xff0c;古语言“工欲善其事必先利其器”。excel是一个好的工具&#xff0c;但是工具里面有很多常用的快捷键&#xff0c;若我们熟记这些快捷键&#xff0c;便可以提高我们的工作效率。本文为持续更新&#xff0c;望有助于搬砖。 1、C…

简单的线程池——从单线程到多线程——从零基础到零基础(站长素材)

多进程&#xff08;Process&#xff09;-读取到数据&#xff0c;要用cpu来运行大量的次数和时间&#xff08;多线程&#xff09;&#xff08;cpu密集型&#xff09;——multiprocessing 多线程&#xff08;Thread&#xff09;-IO多的&#xff0c;同时运行任务数目不多&#xf…

stm32学习笔记-STLINK使用

stm32学习笔记-STLINK使用 使用ST-LINK调试程序进度表格 使用ST-LINK调试程序 说明 组成 总结 记录使用STLINK进行项目的烧写和调试&#xff0c;旨在高效的进行代码调试学习工具包括笔记本、keil5MDK、stm32f030c8t6电表主机、STLINK V2、导线、电表代码总的来说&#xff0…

Kernel 地图

前言 在 Linux Kernel 中&#xff0c;根据 Makefile 和 Kconfig&#xff0c;可以快速地了解一个小的内核子系统。所以我将这两个文件称之为 Kernel 地图。 Kernel 地图 基本上&#xff0c;Linux 内核中&#xff0c;每一个目录下面都有一个 Makefile 和一个 Kconfig 文件。这…

ubuntu 之 zeitgeist-fts 占用内存

座右铭&#xff1a;怎么简单怎么来&#xff0c;以实现功能为主。 欢迎大家关注公众号与我交流 sudo chmod -x /usr/bin/zeitgeist-daemonsudo chmod -x /usr/bin/zeitgeist-datahublocate zeitgeist-ftssudo chmod -x /usr/lib/x86_64-linux-gnu/zeitgeist-fts # 使用 locate z…

星纪魅族宣布 All in AI;欧盟将首次对苹果处以罚款丨 RTE 开发者日报 Vol.146

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

125.乐理基础-五线谱-大六度、小六度

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;124.乐理基础-五线谱-大三度、小三度-CSDN博客 上一个内容里练习的答案&#xff1a; 然后g1到降e2是一个六度&#xff0c;g1到e2也是一个六度&#xff0c;但是它们俩距离是不一样的 然后在六度前面加上大或小&…

盲盒小程序开发:创新科技与消费者心理的完美结合

随着科技的飞速发展&#xff0c;小程序已经深入到我们生活的方方面面。而在众多小程序中&#xff0c;盲盒小程序以其独特的魅力&#xff0c;吸引了大量消费者的关注。本文将探讨盲盒小程序的发展背景、市场需求、开发流程以及未来趋势&#xff0c;以期为相关行业的从业者提供一…

mybatis-plus(五)-mybatis处理多数据源

mybatisplus多数据源 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.6</version> </dependency>配置文件 创建一个数据用户&#x…

【XR806开发板试用】+移植rosserial到XR806

1 XR806简介 板子来源于极术社区的试用&#xff0c;XR806的在线网址 其主要参数&#xff1a; 主控XR806AF2LDDRSIP 288KB SRAM存储SIP 160KB Code ROM. SIP 16Mbit Flash.天线板载WiFi/BT双天线&#xff0c;可共存按键reboot按键 1&#xff0c;功能按键 1灯红色电源指示灯 1…

快速部署MES源码/万界星空科技开源MES

什么是开源MES软件&#xff1f; 开源MES软件是指源代码可以免费获取、修改和分发的MES软件。与传统的商业MES软件相比&#xff0c;开源MES软件具有更高的灵活性和可定制性。企业可以根据自身的需求对软件进行定制化开发&#xff0c;满足不同生产环境下的特定需求。 开源MES软件…

three.js 物体下落动画(重力加速度)

效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><el-button click"loopFun"> 物体下落…

Java 基于 SpringBoot+Vue 的高校招生系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…