【多线程与并发】CompletableFuture用法
原理
CompletableFuture 是 Java 8 引入的一个新的并发编程工具,用于处理异步任务和异步编程。
它提供了一种简单、强大和灵活的方式来处理异步计算、响应式编程和任务组合。
CompletableFuture 相比于传统的 Future 接口,提供了更强大的功能和更好的编程体验。
CompletableFuture 的核心原理可以概括为以下几点:
- 异步任务执行:
• CompletableFuture 可以从 Executor(默认使用 ForkJoinPool.commonPool())中获取线程执行任务,而不是使用主线程进行阻塞。这样可以充分利用多核处理器的性能,提高并行处理能力。 - 链式调用:
• CompletableFuture 提供了一系列的链式调用方法(如 thenApply(), thenCompose(), thenCombine() 等),使得任务之间的依赖关系更加清晰和简洁。开发者可以通过简单的流式调用来编排任务的执行顺序。 - 异常处理:
• CompletableFuture 提供了更灵活和丰富的异常处理机制。可以通过方法链中的 exceptionally() 或 handle() 方法来处理任务执行过程中的异常情况,实现统一的异常处理逻辑。 - 完成回调:
• CompletableFuture 可以注册任务完成的回调函数,当任务完成时自动触发回调。这样可以更方便地处理任务的结果,并进行后续操作。 - 组合任务:
• CompletableFuture 提供了 allOf() 和 anyOf() 等方法,可以组合多个 CompletableFuture 任务的结果。这样可以实现并行执行多个任务并等待它们的结果,或者等待任意一个任务完成。 - 状态管理:
• CompletableFuture 通过内部的 volatile 变量来管理任务的状态(未完成、完成、异常),并使用 CAS(Compare-And-Swap)操作保证线程安全。 - 任务调度机制:
• CompletableFuture 的任务调度机制基于 ForkJoinPool 的工作窃取算法。当一个线程完成当前任务后,会从其他线程的任务队列中窃取任务执行,从而提高 CPU 利用率。
示例与讲解
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class CompletableFutureExample {
public static void main(String[] args) {
// 创建一个异步任务,模拟一个长时间运行的计算
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
return "Hello, World!";
});
// 处理任务结果
future.thenApply(result -> result + " from CompletableFuture")
.thenAccept(System.out::println);
// 处理任务异常
future.exceptionally(ex -> {
System.out.println("An error occurred: " + ex.getMessage());
return "Default result";
});
// 设置超时时间,并处理超时情况
try {
String result = future.get(1, TimeUnit.SECONDS); // 等待任务完成,最多等待1秒
System.out.println("Result: " + result);
} catch (TimeoutException e) {
System.out.println("Task timed out.");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
在这个示例中:
- 异步任务执行:
• 使用CompletableFuture.supplyAsync()
方法提交了一个异步任务,该任务在后台线程中执行并返回结果。 - 链式调用:
• 通过thenApply()
方法对任务结果进行转换,并通过thenAccept()
方法消费结果。 - 异常处理:
• 使用exceptionally()
方法处理任务执行过程中可能发生的异常。 - 超时处理:
• 使用future.get(1, TimeUnit.SECONDS)
方法等待任务完成,最多等待1秒。如果任务在1秒内没有完成,将抛出TimeoutException
,并在 catch 块中进行处理。