首页 > 基础资料 博客日记
CompletableFuture的使用
2023-09-04 17:51:03基础资料围观246次
目录
一、前言
现在大部分的CPU都是多核,我们都知道想要提升我们应用程序的运行效率,就必须得充分利用多核CPU的计算能力;Java为我们提供了大量多线程API,使用它们可以让我们的代码避免同步阻塞,进而达到提升运行效率的目的,CompletableFuture就是其中一个非常强大且重要API,下面我们就来介绍一下CompletableFuture的概念和使用。
二、概念介绍
CompletableFuture 是 Java 8 中新增的一个异步编程工具类,它是基于 Future 和 CompletionStage 接口构建的,可以与 Java 8 中的 Stream API 配合使用,也能够与 Java 9 中的 Reactive Stream API 进行交互。
主要用于异步执行任务并返回结果,实现异步计算和操作组合。它提供了一种灵活、可组合的方式来实现异步计算,同时也提供了异常处理、取消、超时等特性。在CompletableFuture中,我们可以通过回调函数来处理任务的结果,也可以使用其它方法来组合多个CompletableFuture对象,以构建更复杂的异步操作流水线。
三、自身特性
-
异步执行:CompletableFuture 可以在新的线程上异步执行计算或操作,从而不会阻塞主线程,提高程序的响应速度。
-
可组合性:CompletableFuture 的操作可以组合成一个或多个的 CompletableFuture 对象,从而构成复杂的异步计算链。
-
异常处理:CompletableFuture 可以对异常进行处理,通过 exceptionally() 方法可以捕获计算中的异常并返回默认值。
-
取消与超时:CompletableFuture 支持取消异步任务,还可以设置超时时间来避免任务的无限等待。
-
非阻塞式等待:CompletableFuture 提供了非阻塞式的等待方法,如 join() 和 getNow() 方法。
四、使用方式
1、异步执行一个任务并获取结果
通过 CompletableFuture 的静态方法 supplyAsync() 可以异步执行一个任务,返回 CompletableFuture 对象,通过该对象可以获取任务执行的结果。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 执行一些耗时的操作
return "Hello CompletableFuture";
});
String result = future.get(); // 阻塞等待任务执行完成并获取结果
System.out.println(result);
2、异步执行一个任务并处理异常
CompletableFuture 提供了方法 handle() 来处理异步任务执行过程中的异常,它可以处理任务完成时的异常,也可以处理任务执行过程中的异常。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 执行一些可能会出现异常的操作
throw new RuntimeException("Something went wrong");
}).handle((result, exception) -> {
if (exception != null) {
System.out.println("Task failed with exception: " + exception);
return "default value";
} else {
return result;
}
});
String result = future.get();
System.out.println(result);
3、异步执行多个任务并合并结果
通过 CompletableFuture 的静态方法 allOf() 可以并行执行多个任务,等待所有任务完成后,通过 CompletableFuture.join() 方法合并所有任务的结果。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "CompletableFuture");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Java");
CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(future1, future2, future3);
combinedFuture.get();
String result = Stream.of(future1, future2, future3)
.map(CompletableFuture::join)
.collect(Collectors.joining(" "));
System.out.println(result);
CompletableFuture 提供了三种方法来处理它们:handle()、whenComplete() 和 exceptionly()。这里就不做详细介绍了,有兴趣的朋友们可以自己去详细了解一下,以下为各种处理方式的比较结果。
handle() | whenComplete() | exceptionly() | |
访问成功 | Yes | Yes | No |
访问失败 | Yes | Yes | Yes |
能从失败中恢复 | Yes | No | Yes |
能转换结果从T 到 U | Yes | No | No |
成功时触发 | Yes | Yes | No |
失败时触发 | Yes | Yes | Yes |
有异步版本 | Yes | Yes | Yes(12版本) |
4、异步执行多个任务并处理其中一个任务的结果
通过 CompletableFuture 的静态方法 anyOf() 可以并行执行多个任务,只要有一个任务完成,就会立即返回其结果。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Result 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Result 2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Result 3");
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);
Object result = anyOfFuture.get();
System.out.println(result);
5、串行执行多个任务
通过 CompletableFuture 的方法 thenApply()、thenAccept() 和 thenRun() 可以串行执行多个任务,每个任务在前一个任务完成后才会执行。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenApply(result -> result + " CompletableFuture");
CompletableFuture<Void> future3 = future2.thenAccept(result -> System
6、 检查异步任务是否执行完成和执行回调
在CompletableFuture
中,可以使用isDone()
方法来检查异步任务是否已经执行完毕。该方法会返回一个boolean
类型的值,表示异步任务是否已经完成。如果异步任务已经完成,则可以通过调用get()
方法获取其返回值;如果异步任务还没有完成,则可以通过注册回调函数来等待其完成。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 异步任务
return "Hello, World!";
});
// 检查异步任务是否已经完成
if (future.isDone()) {
// 获取异步任务的返回值
String result = future.get();
System.out.println(result);
} else {
// 注册回调函数,在异步任务完成时获取其返回值
future.thenAccept(result -> {
System.out.println(result);
});
}
五、使用场景
在调用第三方同步API时,我们通常需要等待API返回结果后才能继续执行后续代码,这可能会导致系统的吞吐量较低,影响用户的体验。使用CompletableFuture可以在异步执行API请求的同时,继续执行后续代码,从而提高系统的吞吐量。
下面是一个使用CompletableFuture提高系统吞吐量的示例代码。
public class APIService {
public String getDataFromAPI(String url) {
// 同步请求API
String result = request(url);
return result;
}
public CompletableFuture<String> getDataFromAPIAsync(String url) {
// 异步请求API
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> request(url));
return future;
}
private String request(String url) {
// 请求API并返回结果
try {
// 打印线程和请求参数,观察结果帮助理解
System.out.println(Thread.currentThread().getName());
System.out.println(url);
// 睡眠模拟请求耗时
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "success";
}
}
在上面的代码中,getDataFromAPI
方法是同步请求API的方法,会阻塞后续代码的执行。而getDataFromAPIAsync
方法则是使用CompletableFuture
异步请求API的方法,不会阻塞后续代码的执行,而是返回一个CompletableFuture
对象,代表API请求的异步任务。
我们可以在后续代码中继续执行其他任务,等到异步任务完成后再获取结果。
public class Main {
public static void main(String[] args) {
APIService service = new APIService();
CompletableFuture<String> future1 = service.getDataFromAPIAsync("https://api.example.com/data1");
CompletableFuture<String> future2 = service.getDataFromAPIAsync("https://api.example.com/data2");
// 继续执行其他任务
System.out.println("执行其他任务...");
// 等待异步任务完成并获取结果
String result1 = future1.join();
String result2 = future2.join();
// 处理结果
System.out.println("处理结果...");
}
}
在上面的代码中,我们使用了CompletableFuture
异步请求两个API,并在后续代码中继续执行其他任务。当异步任务完成后,我们使用join
方法获取结果,并处理结果。
除了使用join
方法获取结果外,使用get方法也可以获取结果。我们还可以使用thenApply
、thenAccept
、thenCompose
等方法对异步任务的结果进行处理。另外,当我们需要等待多个异步任务的完成并获取结果时,可以使用前面介绍的allOf
和anyOf
方法。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签: