CompletableFuture高级模式详解

news2025/4/18 9:56:59

目录

CompletableFuture高级模式详解

1. CompletableFuture基础概念

1.1 什么是CompletableFuture?

1.2 异步编程基础

1.3 CompletableFuture与Future的对比

2. 创建CompletableFuture

2.1 基本创建方法

2.2 使用异步方法创建

2.3 指定执行器

3. 转换和链式操作

3.1 thenApply - 转换结果

3.2 thenAccept - 消费结果

3.3 thenRun - 执行后续操作

3.4 异步转换操作

4. 组合多个CompletableFuture

4.1 thenCompose - 顺序组合

4.2 thenCombine - 并行组合

4.3 allOf - 等待所有完成

4.4 anyOf - 等待任一完成

5. 异常处理

5.1 exceptionally - 简单异常处理

5.2 handle - 处理结果和异常

5.3 whenComplete - 不改变结果的监听

6. 超时处理

6.1 使用orTimeout方法(Java 9+)

6.2 使用completeOnTimeout方法(Java 9+)

6.3 Java 8中的超时处理

7. 异步执行与线程池

7.1 CompletableFuture默认线程池

7.2 自定义线程池

7.3 异步方法与线程池

8. 高级模式与实战案例

8.1 优雅的API调用模式

8.2 并行任务处理模式

8.3 重试模式

8.4 依赖关系处理模式

9. 最佳实践与常见陷阱

9.1 最佳实践

9.2 常见陷阱

10. 小结

进一步学习资源


1. CompletableFuture基础概念

1.1 什么是CompletableFuture?

CompletableFuture 是Java 8引入的一个类,实现了 FutureCompletionStage 接口,提供了一种更加强大和灵活的方式来进行异步编程。它解决了传统 Future 的多个限制:

  • 传统 Future 不能手动完成
  • 传统 Future 不支持链式操作
  • 传统 Future 没有提供异常处理机制

1.2 异步编程基础

异步编程允许程序在执行耗时操作时不阻塞主线程,提高程序的响应性和性能。异步编程的核心概念:

  • 非阻塞操作:调用后立即返回,不等待执行完成
  • 回调机制:任务完成后执行特定的代码
  • 并行执行:多个任务同时执行
  • 事件驱动:基于事件的处理模型

1.3 CompletableFuture与Future的对比

特性 Future CompletableFuture
手动完成
链式操作
异常处理
组合多个Future
超时处理 需要额外代码 内置支持
回调函数

2. 创建CompletableFuture

2.1 基本创建方法

// 创建一个空的CompletableFuture
CompletableFuture<String> future = new CompletableFuture<>();

// 手动完成一个Future
future.complete("结果");

// 创建一个已完成的Future
CompletableFuture<String> completedFuture = CompletableFuture.completedFuture("已完成");

2.2 使用异步方法创建

// 不返回结果的异步任务
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
    System.out.println("异步任务在执行中...");
    // 执行耗时操作
});

// 返回结果的异步任务
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    System.out.println("异步任务在执行中...");
    // 执行耗时操作
    return "操作结果";
});

2.3 指定执行器

ExecutorService executor = Executors.newFixedThreadPool(5);

// 使用自定义线程池执行异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    System.out.println("使用自定义线程池: " + Thread.currentThread().getName());
    return "操作结果";
}, executor);

3. 转换和链式操作

3.1 thenApply - 转换结果

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");

// 转换结果,String -> String
CompletableFuture<String> future2 = future.thenApply(s -> s + " World");

// 转换结果,String -> Integer
CompletableFuture<Integer> future3 = future.thenApply(String::length);

3.2 thenAccept - 消费结果

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenAccept(s -> System.out.println("得到结果: " + s));
// 不返回结果,仅执行操作

3.3 thenRun - 执行后续操作

CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenRun(() -> System.out.println("操作完成"));
// 不接收参数,也不返回结果

3.4 异步转换操作

// 异步执行thenApply
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
    .thenApplyAsync(s -> {
        System.out.println("转换操作线程: " + Thread.currentThread().getName());
        return s + " World";
    });

// 异步执行thenAccept
CompletableFuture<Void> future2 = CompletableFuture.supplyAsync(() -> "Hello")
    .thenAcceptAsync(s -> {
        System.out.println("消费操作线程: " + Thread.currentThread().getName());
        System.out.println("得到结果: " + s);
    });

4. 组合多个CompletableFuture

4.1 thenCompose - 顺序组合

CompletableFuture<String> getUserInfo(String userId) {
    return CompletableFuture.supplyAsync(() -> "用户信息: " + userId);
}

CompletableFuture<String> getOrderInfo(String userInfo) {
    return CompletableFuture.supplyAsync(() -> userInfo + " 的订单");
}

// 串行执行两个异步操作,第二个操作依赖第一个操作的结果
CompletableFuture<String> result = getUserInfo("12345")
    .thenCompose(this::getOrderInfo);

4.2 thenCombine - 并行组合

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");

// 并行执行两个异步操作,并合并它们的结果
CompletableFuture<String> result = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);

4.3 allOf - 等待所有完成

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "任务1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "任务2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "任务3");

// 等待所有任务完成
CompletableFuture<Void> allDone = CompletableFuture.allOf(future1, future2, future3);

// 等待完成后获取所有结果
CompletableFuture<List<String>> results = allDone.thenApply(v -> {
    return Stream.of(future1, future2, future3)
            .map(CompletableFuture::join)  // join不会抛出检查异常
            .collect(Collectors.toList());
});

4.4 anyOf - 等待任一完成

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "任务1";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "任务2";
});

// 任一任务完成即完成
CompletableFuture<Object> anyResult = CompletableFuture.anyOf(future1, future2);

5. 异常处理

5.1 exceptionally - 简单异常处理

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) {
        throw new RuntimeException("操作失败");
    }
    return "操作成功";
}).exceptionally(ex -> {
    System.out.println("异常: " + ex.getMessage());
    return "默认值";  // 出现异常时返回默认值
});

5.2 handle - 处理结果和异常

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    if (Math.random() > 0.5) {
        throw new RuntimeException("操作失败");
    }
    return "操作成功";
}).handle((result, ex) 

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

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

相关文章

linux下截图工具的选择

方案一 gnome插件Screenshot Tool&#xff08;截屏&#xff09; ksnip&#xff08;图片标注&#xff09; gnome setting设置图片的默认打开方式为ksnip就可以快捷的将Screenshot Tool截屏的图片打开进行标记了。 但是最近我发现Screenshot Tool的延迟截图功能是有问题的&…

rkmpp 解码 精简mpi_dec_test.c例程

rkmpp 解码流程&#xff08;除 MPP_VIDEO_CodingMJPEG 之外&#xff09; 源码 输入h264码流 输出nv12文件 /** Copyright 2015 Rockchip Electronics Co. LTD** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file exce…

怎么构造思维链数据?思维链提示工程的五大原则

我来为您翻译这篇关于思维链提示工程的文章&#xff0c;采用通俗易懂的中文表达&#xff1a; 思维链(CoT)提示工程是生成式AI(GenAI)中一种强大的方法&#xff0c;它能让模型通过逐步推理来解决复杂任务。通过构建引导模型思考过程的提示&#xff0c;思维链能提高输出的准确性…

网络安全之-信息收集

域名收集 域名注册信息 站长之家 https://whois.chinaz.com/ whois 查询的相关网站有:中国万网域名WHOIS信息查询地址: https://whois.aliyun.com/西部数码域名WHOIS信息查询地址: https://whois.west.cn/新网域名WHOIS信息查询地址: http://whois.xinnet.com/domain/whois/in…

JdbcTemplate基本使用

JdbcTemplate概述 它是spring框架中提供的一个对象&#xff0c;是对原始繁琐的JdbcAPI对象的简单封装。spring框架为我们提供了很多的操作模板类。例如:操作关系型数据的JdbcTemplate和MbernateTemplate&#xff0c;操作nosql数据库的RedisTemplate&#xff0c;操作消息队列的…

openEuler24.03 LTS下安装Spark

目录 安装模式介绍 下载Spark 安装Local模式 前提条件 解压安装包 简单使用 安装Standalone模式 前提条件 集群规划 解压安装包 配置Spark 配置Spark-env.sh 配置workers 分发到其他机器 启动集群 简单使用 关闭集群 安装YARN模式 前提条件 解压安装包 配…

使用 DeepSeek API 实现新闻文章地理位置检测与地图可视化

使用 DeepSeek API 实现新闻文章地理位置检测与地图可视化 | Implementing News Article Location Detection and Map Visualization with DeepSeek API 作者&#xff1a;zhutoutoutousan | Author: zhutoutoutousan 发布时间&#xff1a;2025-04-08 | Published: 2025-04-08 标…

如何精准控制大模型的推理深度

论文标题 ThinkEdit: Interpretable Weight Editing to Mitigate Overly Short Thinking in Reasoning Models 论文地址 https://arxiv.org/pdf/2503.22048 代码地址 https://github.com/Trustworthy-ML-Lab/ThinkEdit 作者背景 加州大学圣迭戈分校 动机 链式推理能显…

【力扣hot100题】(078)跳跃游戏Ⅱ

好难啊&#xff0c;我愿称之为跳崖游戏。 依旧用了两种方法&#xff0c;一种是我一开始想到的&#xff0c;一种是看答案学会的。 我自己用的方法是动态规划&#xff0c;维护一个数组记录到该位置的最少步长&#xff0c;每遍历到一个位置就嵌套循环遍历这个位置能到达的位置&a…

WES与WGS数据线粒体DNA数据分析及检测工具

1. 线粒体DNA的异质性 传统的全外显子组测序&#xff08;WES&#xff09;和全基因组测序&#xff08;WGS&#xff09;的二代测序&#xff08;SGS&#xff09; 数据分析流程&#xff0c;能够识别多种类型的基因改变。但大多数用于基因变异分析和注释的工具&#xff0c;在输出文…

word表格间隔设置

1.怎么解决word表格间隔达不到我们想要的要求 其实很简单, 我们直接在word表格里面, 全选表格中里面的内容。接着,我们选择自动调整---->根据内容自动调整表格,即可达到我们想要的要求

SpringBoot 接口限流Lua脚本接合Redis 服务熔断 自定义注解 接口保护

介绍 Spring Boot 接口限流是防止接口被频繁请求而导致服务器负载过重或服务崩溃的一种策略。通过限流&#xff0c;我们可以控制单位时间内允许的请求次数&#xff0c;确保系统的稳定性。限流可以帮助防止恶意请求、保护系统资源&#xff0c;并优化 API 的可用性&#xff0c;避…

I/O进程4

day4 九、信号灯集 1.概念 信号灯(semaphore)&#xff0c;也叫信号量。它是不同进程间或一个给定进程内部不同线程间同步的机制&#xff1b;System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。 通过信号灯集实现共享内存的同步操作。 2.编程…

【语法】C++的list

目录 为什么会有list&#xff1f; 迭代器失效&#xff1a; list和vector的迭代器不同的地方&#xff1a; list的大部分用法和vector都很像&#xff0c;例如push_back&#xff0c;构造&#xff0c;析构&#xff0c;赋值重载这些就不再废话了&#xff0c;本篇主要讲的是和vecto…

【Ai/Agent】Windows11中安装CrewAI过程中的错误解决记录

CrewAi是什么&#xff0c;可以看之下之前写的 《初识CrewAI多智能代理团队协框架》 (注&#xff1a;这篇是基于linux系统下安装实践的) 基于以下记录解决问题后&#xff0c;可以再回到之前的文章继续进行CrewAI的安装 遇到问题 在windows系统中安装 CrewAi 不管是使用 pip 或者…

OSPF的数据报文格式【复习篇】

OSPF协议是跨层封装的协议&#xff08;跨四层封装&#xff09;&#xff0c;直接将应用层的数据封装在网络层协议之后&#xff0c;IP协议包中协议号字段对应的数值为89 OSPF的头部信息&#xff1a; 所有的数据共有的信息字段 字段名描述版本当前OSPF进程使用的版本&#xff08;…

【力扣刷题实战】Z字形变换

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 力扣题目&#xff1a;Z字形变换 题目描述 解题思路 问题理解 算法选择 具体思路 解题要点 完整代码&#xff08;C&#xff09; 兄弟们共勉 &#xff01;&#xff01;&#xff01; 每篇前言 博客主页&#xff1a;小卡…

力扣题解:142. 环形链表 II

在链表学习中&#xff0c;我们已经了解了单链表和双链表&#xff0c;两者的最后一个结点都会指向NULL&#xff1b;今天我们介绍的循环列表则不同&#xff0c;其末尾结点指向的这是链表中的一个结点。 循环链表是一种特殊类型的链表&#xff0c;其尾节点的指针指向头节点&#…

latex模板文件

LaTeX 是一款广泛应用于学术领域的​​文档排版系统​​&#xff0c;尤其以其在数学公式、科学符号和复杂技术文档排版中的强大能力著称。虽然它本身并非专门的“数学软件”&#xff0c;但在处理数学相关内容时表现尤为出色。 1. LaTeX 的核心特点​ 数学公式支持​​&#xff…

BLE 协议栈事件驱动机制详解

在 BlueNRG-LP 等 BLE 系统中,事件驱动是控制状态转移、数据交互和外设协作的基础。本文将深入讲解 BLE 协议栈中事件的来源、分发流程、处理结构与实际工程实践策略,帮助你构建稳定、可维护的 BLE 系统。 📦 一、BLE 事件的来源分类 BLE 协议栈中的事件严格来自协议栈本身…