CompletableFuture
的异步回调机制允许你在一个异步操作完成后执行某些操作,而不需要阻塞当前线程。这个机制使得你可以以非阻塞的方式处理异步结果,并且可以很容易地将多个异步操作串联起来。CompletableFuture
提供了几种方法来注册异步回调,其中最常用的是 thenApply()
, thenAccept()
, 和 thenRun()
方法。
异步回调的概念
- 异步操作:当你提交一个异步任务时,它会在后台线程中执行,而主线程不会被阻塞。
- 回调:异步操作完成后,你可以注册一个回调函数来处理结果。这个回调函数会在任务完成时被自动调用。
示例
假设我们有一个简单的场景,需要异步地计算一个数的平方,并在计算完成后打印结果。我们可以使用 CompletableFuture
来实现这个过程。
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
// 创建一个 CompletableFuture 对象,并提交一个异步任务
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模拟计算任务
try {
Thread.sleep(1000); // 模拟延迟
} catch (InterruptedException e) {
e.printStackTrace();
}
return 5; // 计算结果
});
// 注册一个回调函数,当 future 完成时计算平方并打印
future.thenApply(result -> {
// 计算平方
int squared = result * result;
return squared;
}).thenAccept(squaredResult -> {
// 打印结果
System.out.println("Squared Result: " + squaredResult);
});
// 主线程继续做其他事情
System.out.println("Main thread is not blocked");
// 等待 CompletableFuture 完成,以确保主线程不会提前结束
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//输出结果
/**
Main thread is not blocked
Squared Result: 25
*/
详细说明
-
创建 CompletableFuture:
CompletableFuture.supplyAsync()
方法启动一个异步任务。在这个例子中,它在后台线程中计算一个数的值(模拟了延迟)。 -
注册回调函数:
thenApply(result -> { ... })
:这个回调函数在异步任务完成后执行。它接收异步任务的结果(在这里是5
),并计算它的平方。thenAccept(squaredResult -> { ... })
:这个回调函数在上一个回调函数完成后执行。它接收平方的结果,并将其打印到控制台。
-
主线程:在创建
CompletableFuture
并注册回调后,主线程继续执行其他操作(在这里是打印一条消息)。主线程不会被阻塞,仍然可以进行其他任务。 -
等待任务完成:为了确保主线程在程序结束前等待异步任务完成,我们使用
future.get()
。在实际应用中,这种等待可能是不必要的,因为你可以通过其他机制确保主线程不会提前结束。
总结
CompletableFuture
的异步回调机制使得你可以优雅地处理异步操作的结果,而不需要显式地管理线程或处理复杂的回调地狱问题。通过注册多个回调函数,你可以实现复杂的异步操作链。