在Java的多线程编程中,FutureTask
和 CompletableFuture
是两个关键的工具,分别代表了基础和进阶的异步编程技术。本文将深入介绍这两者的特点、使用方法以及它们之间的巧妙应用、区别以及各自的优缺点。
FutureTask
是一个实现了 Future
接口的可取消异步计算任务。它简化了异步任务的处理,能够方便地执行和获取结果。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<String> {
public String call() throws Exception {
// 执行耗时操作
return "Task completed!";
}
}
public class FutureTaskExample {
public static void main(String[] args) {
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask).start();
try {
String result = futureTask.get();
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
CompletableFuture
是Java 8引入的强大异步编程工具。它支持链式调用、多个异步任务组合、异常处理等特性,使得异步编程更为灵活。
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 执行耗时操作
return "Task completed!";
});
future.thenAccept(result -> System.out.println(result));
try {
future.get();
} catch (Exception e) {
e.printStackTrace();
}
}
}
另外这CompletableFuture
是一个功能强大的类,提供了丰富的方法来支持异步编程的各种需求。除了上文提到的 supplyAsync
和 thenAccept
,下面是一些 CompletableFuture
中常用的方法:
thenApply
方法用于对 CompletableFuture
的结果进行转换。它接受一个 Function
参数,该函数会在异步任务完成后被应用于结果,并返回一个新的 CompletableFuture
,其中包含转换后的结果。
CompletableFuture<String> originalFuture = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<Integer> transformedFuture = originalFuture.thenApply(s -> s.length());
thenCompose
方法用于连接两个异步任务,将它们的结果合并成一个新的 CompletableFuture
。它接受一个 Function
参数,该函数返回一个新的 CompletableFuture
。
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> " World");
CompletableFuture<String> combinedFuture = firstFuture.thenCompose(s -> secondFuture.thenApply(t -> s + t));
thenCombine
方法用于组合两个独立的 CompletableFuture
的结果。它接受两个参数:第一个是另一个 CompletableFuture
,第二个是一个 BiFunction
,用于合并两个结果。
CompletableFuture<String> firstFuture = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> secondFuture = CompletableFuture.supplyAsync(() -> " World");
CompletableFuture<String> combinedFuture = firstFuture.thenCombine(secondFuture, (s, t) -> s + t);
exceptionally
方法用于处理异常情况。它接受一个 Function
参数,该函数在异步任务发生异常时被执行,返回一个替代值或者另一个异步任务。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟异常
throw new RuntimeException("Error");
});
CompletableFuture<String> result = future.exceptionally(ex -> "Handled Exception");
handle
方法类似于 exceptionally
,但它能处理正常结果和异常。它接受一个 BiFunction
参数,该函数在异步任务完成时被执行,可以处理正常结果或异常。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> result = future.handle((res, ex) -> {
if (ex != null) {
return "Handled Exception";
} else {
return res.toUpperCase();
}
});
allOf
方法接受一个 CompletableFuture
数组,返回一个新的 CompletableFuture
,当数组中的所有任务都完成时,新的 CompletableFuture
才会完成。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2);
anyOf
方法也接受一个 CompletableFuture
数组,但返回的 CompletableFuture
在数组中的任意一个任务完成时就会完成。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2);
以上只是 CompletableFuture
中一部分常用方法,它还提供了更多用于处理超时、取消任务等功能的方法。使用这些方法,你可以更灵活地处理异步编程中的各种情况,提高代码的可读性和可维护性。
ExecutorService
进行线程池管理时。FutureTask
不直接支持多个异步任务的组合,而 CompletableFuture
提供了一系列方法,如 thenCompose
、thenCombine
等,支持多个异步任务的组合和协同执行。CompletableFuture
更灵活地支持异常处理,能够通过 exceptionally
或 handle
方法处理异步任务中的异常,而 FutureTask
的异常处理相对简单。FutureTask
和 CompletableFuture
分别代表了Java异步编程的两个不同层次。选择使用哪个取决于项目需求的复杂度和对异步编程功能的需求。在实际应用中,你可能会根据具体场景选择灵活的 CompletableFuture
或者简单的 FutureTask
,以提高代码的可读性和维护性。希望通过深入了解这两者,你能够在异步编程的领域中更得心应手。