Java异步方法CompletableFuture类的使用

news/2024/11/22 18:37:22/

Java中常用的异步方法

1、使用线程:你可以创建一个新的线程来执行异步操作。这可以通过直接创建Thread对象并启动它,或者使用线程池来管理线程的生命周期。

new Thread(() -> {// 异步操作代码
}).start();

2、使用线程池Executor框架:Executor框架提供了一种更高级别的异步执行机制,可以管理线程池和任务调度。

ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(() -> {// 异步操作代码
});
executor.shutdown();

3、使用Java 8引入的CompletableFuture类:CompletableFuture类提供了一种更便捷的方式来执行异步操作,并处理操作完成后的结果。

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {// 异步操作代码
});// 可以在异步操作完成后执行回调函数
future.thenRun(() -> {// 操作完成后的处理代码
});

4、使用第三方库:除了Java内置的工具,还有许多第三方库可用于实现异步操作,例如Guava的ListenableFuture等。

CompletableFuture类使用

CompletableFuture 类是 Java 中用于处理异步编程的强大工具。下面是 CompletableFuture 类的一些常用方法的详细解释: 

1.  supplyAsync(Supplier<U> supplier) :创建一个 CompletableFuture,该 CompletableFuture 会异步执行 Supplier 方法,并返回计算结果。  

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 异步操作:计算两个整数的和int a = 5;int b = 10;return a + b;
});
// get() 方法,该方法是阻塞的,直到异步操作完成或超时。
Integer val = future.get();
System.out.println("获取异步加载的值:" + val);

2.  thenApply(Function<? super T,? extends U> fn) :在 CompletableFuture 完成后应用给定的函数 fn,将 CompletableFuture 的结果转换为另一种类型,并返回一个新的 CompletableFuture。  

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 异步操作:获取用户年龄return getUserAge();
}).thenApply(age -> {// 将年龄转换为字符串return "返回用户年龄信息: " + String.valueOf(age);
});

3.  thenAccept(Consumer<? super T> action) :在 CompletableFuture 完成后执行给定的动作 action,对 CompletableFuture 的结果进行消费,但不返回新的 CompletableFuture。  

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {// 异步操作:获取用户年龄return getUserAge();
}).thenAccept(age -> {// 没有返回值System.out.println("thenAccept没有返回值: " + String.valueOf(age));
});

4.  thenRun(Runnable action) :在 CompletableFuture 完成后执行给定的动作 action,对 CompletableFuture 的结果不进行消费,也不返回新的 CompletableFuture。  

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 返回值return "Result";
});CompletableFuture<Void> thenRunFuture = future.thenRun(() -> {// 使用 thenRun() 执行一个操作,在计算完成后打印一条消息System.out.println("执行完成!");
});// 获取值
thenRunFuture.get();

5.  thenCompose(Function<? super T,? extends CompletionStage<U>> fn) :在 CompletableFuture 完成后应用给定的函数 fn,将 CompletableFuture 的结果传递给该函数,并返回一个新的 CompletableFuture。简单的说就是用于将两个 CompletableFuture 对象串联起来执行。

// 使用场景:
// 假设有两个异步任务,任务 A 返回一个结果,任务 B 根据任务 A 的结果进行计算并返回最终结果。
CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> {// 异步任务 Areturn 2;
});CompletableFuture<Integer> futureB = futureA.thenCompose(resultA -> {// 异步任务 B,根据任务 A 的结果进行计算int resultB = resultA * 3;return CompletableFuture.completedFuture(resultB);
});// 最终结果输出6
futureB.thenAccept(finalResult -> System.out.println("最终结果:" + finalResult));

6.  exceptionally(Function<Throwable,? extends T> fn) :在 CompletableFuture 发生异常时应用给定的函数 fn,返回一个新的 CompletableFuture,该 CompletableFuture 的结果是由异常处理函数提供的,用于处理异步任务中的异常情况.

// 使用场景:
// 假设有一个异步任务,计算两个数的商,出现除零异常。在发生异常时返回一个默认值
CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {int dividend = 10;int divisor = 0;return dividend / divisor;
});CompletableFuture<Double> resultFuture = future.exceptionally(ex -> {System.out.println("发生异常:" + ex);return 0.0; // 返回默认值
});// 输出:
// 发生异常:java.lang.ArithmeticException: / by zero
// 计算结果:0.0
resultFuture.thenAccept(result -> System.out.println("计算结果:" + result));

7.  handle(BiFunction<? super T,Throwable,? extends U> fn) :在 CompletableFuture 完成后应用给定的函数 fn,无论 CompletableFuture 是否发生异常,该函数都会被调用,并返回一个新的 CompletableFuture,用于处理异步任务的结果(包括正常结果和异常情况)。

CompletableFuture<Double> future = CompletableFuture.supplyAsync(() -> {int dividend = 10;int divisor = 2;return dividend / divisor;
});CompletableFuture<String> resultFuture = future.handle((result, ex) -> {if (ex != null) {System.out.println("发生异常:" + ex);return "默认值"; // 返回默认值} else {return "计算结果:" + result;}
});// 输出:
// 计算结果:5.0
resultFuture.thenAccept(result -> System.out.println(result));

8.  allOf(CompletableFuture<?>... cfs) :等待多个 CompletableFuture 完成,并返回一个新的 CompletableFuture,该新的 CompletableFuture 在所有输入的 CompletableFuture 都完成后才会完成。 

注意:allOf() 方法返回的是 CompletableFuture<Void> ,因为它只关注所有CompletableFuture的完成状态,而不关心具体的结果。如果你需要获取每个CompletableFuture的结果,你可以在 allOf() 之后使用 get() 方法来获取每个CompletableFuture的结果。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureExample {public static void main(String[] args) {CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 2";});CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 3";});CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);try {allFutures.get();System.out.println("所有任务都完成了,开始获取值:");System.out.println("获取 Future 1 的值: " + future1.get());System.out.println("获取 Future 2 的值: " + future2.get());System.out.println("获取 Future 3 的值: " + future3.get());} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

9.  anyOf(CompletableFuture<?>... cfs) :等待多个 CompletableFuture 中的任意一个完成,并返回一个新的 CompletableFuture,该新的 CompletableFuture 在其中任意一个 CompletableFuture 完成时就会完成。 

CompletableFuture.anyOf() 方法常用于以下场景:当你想并发执行多个异步任务,并且只需要获取第一个完成的任务的结果时,它非常有用。在有多个独立任务且只关心第一个成功完成的任务结果时,它可以发挥作用。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;public class CompletableFutureExample {public static void main(String[] args) {CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 2";});CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "Result from Future 3";});CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2, future3);try {System.out.println("打印任务的完成状态: " + anyFuture.isDone());Object result = anyFuture.get();System.out.println("有一个任务完成了,就不管别的任务了: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}

Future 和 AsyncResult的区别和使用场景

1. Future 接口: 
   - Future 接口是 Java 提供的一个异步操作的结果的占位符。它表示一个可能完成或者失败的异步操作。 
   - Future 接口提供了一些方法(如  get() 、 isDone() 、 cancel()  等)来获取异步操作的结果、检查操作是否完成以及取消操作。 
   - Future 接口的一个主要限制是它只能通过轮询来判断异步操作是否完成,这样可能会导致线程阻塞。 

// get()获取值
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!");
String result = future.get();
System.out.println("阻塞直到获取值" + result);// isDone()是否完成
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!");
boolean done = future.isDone();
System.out.println("任务是否完成:" + done);// cancel()取消异步任务的执行
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {// 模拟一个长时间运行的任务try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}return "Hello, World!";
});
boolean canceled = future.cancel(true);
System.out.println("任务是否被取消:" + canceled);

2. AsyncResult 接口: 
   - AsyncResult 接口是 Vert.x 框架中的一个特定实现,用于表示异步操作的结果。 
   - AsyncResult 接口继承自 Future 接口,并提供了更多的方法和功能,使得处理异步操作更加方便。 
   - AsyncResult 接口提供了一种更灵活的方式来处理异步操作的结果,包括处理成功和失败的情况,并可以获取操作的异常信息。 

// 此处使用了异步注解、结合AsyncResult使用的举例
@Async(THREAD_NAME)
public Future<Integer> ruleTotal() {return new AsyncResult<Integer>(testMapper.obtainCount());
}


http://www.ppmy.cn/news/1035609.html

相关文章

【C语言实战项目】通讯录

一.了解项目功能 在本次实战项目中我们的目标是实现一个通讯录: 该通讯录可以用来存储1000个人的信息 每个人的信息包括&#xff1a;姓名、年龄、性别、住址、电话 通讯录提供功能有&#xff1a; 添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有…

SSM——用户、角色、权限操作

1. 数据库与表结构 1.1 用户表 1.1.1 用户表信息描述 users 1.1.2 sql语句 CREATE TABLE users( id varchar2(32) default SYS_GUID() PRIMARY KEY, email VARCHAR2(50) UNIQUE NOT NULL, username VARCHAR2(50), PASSWORD VARCHAR2(50), phoneNum VARCHAR2(20), STATUS INT…

华创云鼎面试:java后端开发

华创云鼎面试: 1、项目:项目业务介绍、项目人员组成 2、分布式锁用过哪些 基于数据库的锁&#xff1a;可以使用关系型数据库的事务和行级锁来实现分布式锁。通过在数据库中创建一个标志位或特定的锁表来表示资源的锁定状态&#xff0c;其他进程在访问该资源之前需要先获取该锁…

css浮动(为什么要清除浮动?清除浮动有哪几种方式?)

为什么要清除浮动&#xff1f; 清除浮动主要是为了清除浮动元素造成的影响&#xff0c;使浮动元素不会影响其后元素的布局 防止父元素高度塌陷&#xff1a;当元素浮动后&#xff0c;它会脱离一个标准文档流&#xff0c;不再占用原先的布局空间。如果一个父元素内只有浮动元素&a…

Linux 设置 ssh 内网穿透

背景&#xff1a;有三台机器A、B、C&#xff0c;机器 A 位于某局域网内&#xff0c;能够连接到互联网。机器 B 有公网 IP&#xff0c;能被 A 访问到。机器 C 位于另外一个局域网内&#xff0c;能够连接到互联网&#xff0c;能够访问 B。 目标&#xff1a;以 B 为中介&#xff…

ASP.NET WEB API通过SugarSql连接MySQL数据库

注意&#xff1a;VS2022企业版可以&#xff0c;社区版可能存在问题。实体名称和字段和数据库中的要一致。 1、创建项目&#xff0c;安装SqlSugarCore、Pomelo.EntityFrameworkCore.MySql插件 2、文件结构 2、appsettings.json { “Logging”: { “LogLevel”: { “Default”: …

给对象添加新的属性

使用点 let obj {} obj.name "zy"使用方括号 let obj {} obj[name] "zy"使用assign 也以用来复制对象。 Object.assign({},{name:zy,age:10})扩展运算符 ES6新增语法&#xff0c;可以将两个对象合并成一个对象。 let obj1 {appid:"office&…

如何卖 Click to WhatsApp 广告最有效

2022年&#xff0c;大多数直接面向消费者的品牌都面临相同挑战—— Facebook 和 Instagram 的广告成本大幅增加。Business Insider 报导指出&#xff0c;2021年 Facebook 广告每次点击的平均成本&#xff08;average cost per click&#xff09;达到0.974美元&#xff0c;按年升…