Java中CompletableFuture异步工具类

参考:CompletableFuture 详解 | JavaGuide

实际项目中,一个接口可能需要同时获取多种不同的数据,然后再汇总返回,举个例子:用户请求获取订单信息,可能需要同时获取用户信息、商品详情、物流信息、等数据。

如果是串行(按顺序依次执行每个任务)执行的话,接口的响应速度会非常慢。

考虑到这些任务之间有大部分都是 无前后顺序关联 的,可以 并行执行 ,就比如说调用获取商品详情的时候,可以同时调用获取物流信息。通过并行执行多个任务的方式,接口的响应速度会得到大幅优化。

Future介绍

Future是Java5引入的接口,提供了基本的异步处理功能,但它的局限性在于只能通过 get()方法阻塞获取结果,无法链式调用多个任务,也缺 少异常处理机制。

CompletableFuture 是 Future 的增强版,提供了非阻塞的结果处理、任务组合和异常处理,使得异步编程更加灵活和强大。

在 Java 中,Future 只是一个泛型接口,位于 java.util.concurrent 包下,其中定义了 5 个方法,主要包括下面这 4 个功能:

  • 取消任务;

  • 判断任务是否被取消;

  • 判断任务是否已经执行完成;

  • 获取任务执行结果。

// V 代表了Future执行的任务返回值的类型
public interface Future<V> {// 取消任务执行// 成功取消返回 true,否则返回 falseboolean cancel(boolean mayInterruptIfRunning);// 判断任务是否被取消boolean isCancelled();// 判断任务是否已经执行完成boolean isDone();// 获取任务执行结果V get() throws InterruptedException, ExecutionException;// 指定时间内没有返回计算结果就抛出 TimeOutException 异常V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutExceptio
}

CompletableFuture是 java 8引入的一个强大的异步工具类。允许非阻塞地处理异步任务,并且可以通过链式调用组合多个异步操作。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
}

核心特性如下:

  1. 异步执行

    通过runAsyncsupplyAsync方法,可以异步地执行任务。

  2. 任务完成回调

    使用thenApply、thenAccept、thenRun等方法,可以在任务完成后执行回调。

  3. 任务组合

    可以将多个 CompletableFuture 组合在一起,通过 thenCombine、thenCompose 等方法,处理多个异步任务之间的依赖关系。

  4. 异常处理

    提供了exceptionally、handle等方法,可以在异步任务发生异常时进行处理。

  5. 并行处理

    可以通过allOfanyOf方法,并行地执行多个异步任务,并在所有任务完成或任意一个任务完成时执行回调。

扩展

创建异步任务
  • 通过 new 关键字

CompletableFuture<RpcResponse<Object>> resultFuture = new CompletableFuture<>();
//获取异步计算的结果,调用 get() 方法的线程会 阻塞 直到 CompletableFuture 完成运算
rpcResponse = completableFuture.get();  
// complete() 方法只能调用一次,后续调用将被忽略。
resultFuture.complete(rpcResponse);
​
//如果你已经知道计算的结果的话,可以使用静态方法 completedFuture() 来创建 CompletableFuture 
CompletableFuture<String> future = CompletableFuture.completedFuture("hello!");
assertEquals("hello!", future.get());
  • runAsync: 创建异步任务,不返回结果

  • supplyAsync: 创建异步任务并返回结果

CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {  //前面的这个future1不是用来接收数据的,仅仅表示完成状态// 异步任务
});
​
//future2接收异步执行的结果,即里面返回出来的字符串,后续可以利用thenAccept等方法处理这个结果
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { // 异步任务并返回结果return "Hello, nihao.com!";
});
任务完成回调
  • thenApply: 在任务完成后可以对任务结果进行转换返回

  • thenAccept: 在任务完成后对结果进行消费,但不返回新结果

  • thenRun: 在任务完成后执行一个操作,但不需要使用任务结果

// 转换任务结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello").thenApply(result -> result + " nihao.com");// 消费任务结果,不返回新结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello").thenAccept(result -> System.out.println(result));// 不消费任务结果,也不返回新结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
.thenRun(() -> System.out.println("Task finished"));
任务组合
  • thenCombine: 合并两个CompletableFuture 的结果

  • thenCompose: 将一个CompletableFuture 的结果作为另一个 CompletableFuture 的输入。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");   //1
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "nihao");   //2
​
//future1.thenComebine(fu2,...) 
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
​
//将前者的result 传给 后者
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello").thenCompose(result -> CompletableFuture.supplyAsync(() -> result + " nihao"));
异常处理
  • exceptionally: 在任务发生异常时提供默认值。

  • handle: 在任务完成或发生异常时进行处理。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (true) {throw new RuntimeException("Exception");}return "Hello";
}).exceptionally(ex -> "nihao");     //提供发生异常时的默认值
​
​
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (true) {throw new RuntimeException("Exception");}return "Hello";
}).handle((result, ex) -> {       //提供发生异常后的处理if (ex != null) {return "Default Value";}return result;
});
并行处理
  • allOf: 等待多个CompletableFuture 全部完成

  • anyOf: 任意一个 CompletableFuture 完成时执行操作

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
allFutures.thenRun(() -> System.out.println("nihao tasks finished"));    //全部完成在执行
​
​
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
anyFuture.thenAccept(result -> System.out.println("nihao task finished with result: " + result));  //任意一个完成即可执行
使用建议
  • CompletableFuture 默认使用全局共享的 ForkJoinPool.commonPool() 作为执行器,所以应用程序、多个库或框架(如 Spring、第三方库)若都依赖 CompletableFuture,默认情况下它们都会共享同一个线程池。

  • 为避免这些问题,建议为 CompletableFuture 提供自定义线程池,根据任务特性调整线程池大小和队列类型,也更好地处理线程中的异常情况

  • CompletableFutureget()方法是阻塞的,尽量避免使用。如果必须要使用的话,需要添加超时时间,否则可能会导致主线程一直等待,无法执行其他任务。

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

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

相关文章

Oracle Rac 多路径链路不稳定引发IO降速-光弱

一、背景 今天突然被异地的同事拉来开远程会议&#xff0c;会议内容是开发反馈每天9点左右有个sqlldr 命令的脚本调用突然执行很慢&#xff0c;以前几秒的导入操作现在需要30-60s左右&#xff0c;而且数据量基本相同。 二、分析 1&#xff09;、查看ASH报告 从报告上确认是数…

哈希表-两个数的交集

代码随想录-刷题笔记 349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 内容: 集合的使用 , 重复的数剔除掉&#xff0c;剩下的即为交集&#xff0c;最后加入数组即可。 class Solution {public int[] intersection(int[] nums1, int[] nums2) {Set<Integer…

[JVM篇]分代垃圾回收

分代垃圾回收 分代收集法是目前大部分 JVM 所采用的方法&#xff0c;其核心思想是根据对象存活的不同生命周期将内存划分为不同的域&#xff0c;一般情况下将 GC 堆划分为老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特点是每次垃圾回收时只有少量对象…

汉诺塔问题详解:递归与分治的经典案例

嘿&#xff0c;小伙伴们&#xff01;今天我可算撞见了个超有意思的东西&#xff0c;就是那大名鼎鼎的汉诺塔问题&#xff01;我这好奇心一下子就被勾起来了&#xff0c;迫不及待地想深挖一下&#xff0c;然后把那些好玩的、烧脑的、让人拍案叫绝的解题思路和奇妙故事都分享给大…

vue中如何动态的增减组件的类名(class)

在 Vue.js 2 中&#xff0c;你可以通过计算属性或直接在模板中使用 v-bind:class 来动态地改变组件的类名。下面是一个简单的示例&#xff0c;说明如何在某个条件被复核后为组件添加一个 selected 类&#xff08;此处为组件添加一个默认的类&#xff08;例如 radio&#xff09;…

Vue3 基础概念与环境搭建

一、Vue3 简介 Vue3 是 Vue.js 的最新主要版本&#xff0c;于 2020 年 9 月正式发布。它在性能、可维护性和开发体验方面都有了显著的改进。相比 Vue2&#xff0c;Vue3 的主要特点包括&#xff1a; 更高效的响应式系统&#xff1a;使用 Proxy替代了 Object.defineProperty&…

华为昇腾920b服务器部署DeepSeek翻车现场

最近到祸一台HUAWEI Kunpeng 920 5250&#xff0c;先看看配置。之前是部署的讯飞大模型&#xff0c;发现资源利用率太低了。把5台减少到3台&#xff0c;就出了他 硬件配置信息 基本硬件信息 按照惯例先来看看配置。一共3块盘&#xff0c;500G的系统盘&#xff0c; 2块3T固态…

Python的那些事第二十三篇:Express(Node.js)与 Python:一场跨语言的浪漫邂逅

摘要 在当今的编程世界里,Node.js 和 Python 像是两个性格迥异的超级英雄,一个以速度和灵活性著称,另一个则以强大和优雅闻名。本文将探讨如何通过 Express 框架将 Node.js 和 Python 结合起来,打造出一个高效、有趣的 Web 应用。我们将通过一系列幽默风趣的实例和表格,展…

Word中接入大模型教程

前言 为什么要在word中接入大模型呢&#xff1f; 个人觉得最大的意义就是不用来回切换与复制粘贴了吧。 今天分享一下昨天实践的在word中接入大模型的教程。 在word中接入大模型最简单的方式就是使用vba。 vba代码要做的事&#xff0c;拆分一下就是&#xff1a; 获取用户…

open3d绘制平面

在Open3D中绘制平面通常涉及到创建一个平面模型并将其可视化。Open3D是一个开源库,主要用于3D数据的处理和可视化,但它主要用于3D数据的处理,并不直接支持绘制2D平面。如果你想在Open3D中“绘制”一个平面,你可以通过以下几种方法来实现类似的效果: 方法1:使用o3d.geome…

DeepSeek R1 与 OpenAI O1:机器学习模型的巅峰对决

我的个人主页 我的专栏&#xff1a;人工智能领域、java-数据结构、Javase、C语言&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞&#x1f44d;收藏❤ 一、引言 在机器学习的广袤天地中&#xff0c;大型语言模型&#xff08;LLM&#xff09;无疑是最…

WebGPU顶点插槽进阶优化指南:释放GPU渲染性能

本文基于WebGPU官方规范与实践经验&#xff0c;深入探讨顶点缓冲区的性能优化策略&#xff0c;涵盖数据布局、资源管理、渲染流程等多个维度&#xff0c;并附详细代码注释与性能对比分析。 一、数据布局优化&#xff1a;降低内存与带宽压力 1. 内存对齐策略 GPU对内存访问有严…

数据结构实现顺序表的尾插,尾删,按值查找/修改/删除,按下标查找/增加/删除

头文件&#xff1a;head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXSIZE 20enum num {success,false-1};typedef int datatype;typedef struct {int len;datatype data[MAXSIZE]; }S…

基于Spring Boot+Vue的宠物服务管理系统(源码+文档)

项目简介 宠物服务管理系统实现了以下功能&#xff1a; 基于Spring BootVue的宠物服务管理系统的主要使用者分为用户管理模块&#xff0c;由于系统运行在互联网络中&#xff0c;一些游客或者病毒恶意进行注册&#xff0c;产生大量的垃圾用户信息&#xff0c;管理员可以对这些…

2. grafana插件安装并接入zabbix

一、在线安装 如果不指定安装位置&#xff0c;则默认安装位置为/var/lib/grafana/plugins 插件安装完成之后需要重启grafana 命令在上一篇讲到过 //查看相关帮助 [rootlocalhost ~]# grafana-cli plugins --help //从列举中的插件过滤zabbix插件 [rootlocalhost ~]# grafana…

【Linux】Ubuntu Linux 系统——Python集成开发环境

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;明天就周五了&#xff0c;再坚持坚持又能休息了&#xff01;&#xff01;&#x1f606; 本文是有关Linux 操作系统中Python集成开发环境基础知识&#xff0c;后续将添加更多相关知识噢&#xff0c;谢谢各位…

DeepSeek+即梦 做AI视频

DeepSeek做AI视频 制作流程第一步&#xff1a;DeepSeek 生成视频脚本和分镜 第二步&#xff1a;生成分镜图片绘画提示词第三步&#xff1a;生成分镜图片第四步&#xff1a;使用可灵 AI 工具&#xff0c;将生成的图片转成视频。第五步&#xff1a;剪映成短视频 DeepSeek 真的强&…

react传递函数与回调函数原理

为什么 React 允许直接传递函数&#xff1f; 回调函数核心逻辑 例子&#xff1a;父组件控制 Modal 的显示与隐藏 // 父组件 (ParentComponent.tsx) import React, { useState } from react; import { Modal, Button } from antd; import ModalContent from ./ModalContent;co…

【Spring AI】基于SpringAI+Vue3+ElementPlus的QA系统实现(前端)

整理不易&#xff0c;请不要吝啬你的赞和收藏。 1. 前言 这篇文章是 Spring AI Q&A 系统的前端实现。这篇文章将介绍如何快速搭建一个基于 vue3 ElementPlus 的前端项目&#xff0c;vue3 项目的目录结构介绍&#xff0c;如何在前端实现流式响应&#xff0c;如何高亮显示…

企业级API集成方案:基于阿里云函数计算调用DeepSeek全解析

解决方案链接&#xff1a;https://www.aliyun.com/solution/tech-solution/deepseek-r1-for-platforms?utm_contentg_1000401616 何为DeepSeek R1 DeepSeek R1模型有诸多技术优势。高效架构设计使其能更高效提取特征&#xff0c;减少冗余计算&#xff0c;提升数据处理速度、…