大家好,我是程序员牛肉。
不知道你们在使用多线程的时候会用什么方式来获取异步结果?大多数人接触的首个方法肯定是使用Future来获取异步结果。
让我们先看一下一整个Future的结构图
[Future 是 Java 并发包(java.util.concurrent)中的一个接口,用于表示一个异步计算的结果。它提供了一种机制,可以在异步任务完成后获取结果或处理异常。]
使用Future的方法很简单,如下图所示:
List<Future<Void>> futures = new ArrayList<>();
for (OrderDTO order : ListResponse.getOrders(){
futures.add(threadPool.submit(() -> {
itemList.add(order);
return null;}));
}
这样的话,我们就可以获取所有执行任务线程的Future对象,通过这个对象,我们可以对执行任务的线程进行一些操作:
虽然基于Future我们对线程有了更加高的操作自由,但它也有自己的缺点。
1.Future接口中没有关于异常处理的方法,这对于我们的项目开发来讲是一个很憋屈的点。使用Future的时候需要我们在任务执行时捕获异常,然后将异常封装到 Future 对象中返回。
2.Future的不支持组合多个异步任务的结果,如果要处理多个异步任务之间的依赖或者组合,需要我们手动完成。
这么明显的缺点我们都能发现,那么更不要提那些维护Java的核心开发者了。
于是Java8狠活来袭,Java核心开发者引入了Completablefuture来解决我们上述提到的这两个问题。
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html 对应的官方文档
而我们这一篇主要介绍一下Completablefuture类中的常用方法。
1.runAsync: 执行异步计算,但是不会返回结果。该方法接受一个Runnable对象并且返回一个CompletableFuture<Void>。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
System.out.println("Task is running in a separate thread: " + Thread.currentThread().getName());
Thread.sleep(2000); // 模拟耗时操作
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
System.out.println("Task completed!");
});
2.supplyAsync: 执行异步计算,并返回结果。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 任务内容:模拟长时间运行的任务
try {
System.out.println("Task is running in a separate thread: " + Thread.currentThread().getName());
Thread.sleep(2000); // 模拟耗时操作
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Task completed!";
});
3.thenApply :thenApply 方法用于在 CompletableFuture 完成后,对其结果进行转换或处理,并返回一个新的 CompletableFuture。
public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn)
代码实例:
public class CompletableFutureThenApplyExample {
public static void main(String[] args) {
// 创建一个异步任务,返回一个整数
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("Calculating... in thread: " + Thread.currentThread().getName());
return 42; // 模拟一个计算结果
});
// 使用 thenApply 对结果进行转换,将整数转换为字符串
CompletableFuture<String> stringFuture = future.thenApply(result -> {
System.out.println("Transforming result in thread: " + Thread.currentThread().getName());
return "The answer is " + (result+1);
});
}
}
}
基于thenApply,我们实现了对CompletableFuture的结果进行的二次处理。需要注意的是thenApply在执行的时候,使用的是执行CompletableFuture的线程。
既然有这种两个任务是同一个线程处理的,那就有两个任务不是同一个线程处理的方法,它的名字叫做thenApplyAsync。
对比thenApplyAsync和thenApply的源码,会发现thenApplyAsync只不过是在提交参数的时候多提交了一个线程池。
4.thenAccept thenAccept 方法用于在 CompletableFuture 完成后,对其结果进行转换或处理。这个方法只消费,没有返回值。
代码例子就不举了,有点水字数的嫌疑了,参考看一下thenApply的代码就好了。
同理thenAccept在处理时使用的也是执行CompletableFuture的线程。而如果想要新开一个线程来处理thenAccept方法的话,可以使thenApplyAsync。
5.CompletableFuture.allOf() : 他是一个静态方法,用于组合多个方法,当所有的Completablefuture方法都完成的时候,返回的 CompletableFuture<Void> 也将完成。这在需要等待多个并发任务全部完成时非常有用。
public static void main(String[] args) {
CompletableFuture<Void> allOfFutures = CompletableFuture.allOf(future1, future2);
allOfFutures.thenRun(() -> System.out.println("All tasks completed"));
}
6.CompletableFuture.anyOf:等待任意一个给定的 CompletableFuture 完成。
public static void main(String[] args) {
CompletableFuture<Object> anyOfFutures = CompletableFuture.anyOf(future1, future2);
anyOfFutures.thenAccept(result -> System.out.println("First completed task result: " + result));
}
除此之外还有CompletableFuture还有一些方法没有被介绍,但这些内容一问GPT就知道了,没必要在这里赘述。
今天关于CompletableFuture的介绍就到这里了,本篇也主要是向大家介绍这么一个异步工具类去使用,不涉及底层原理。希望我的文章可以帮到你。
对于CompletableFuture你有什么想说的嘛?欢迎在评论区留言。
关注我,带你了解更多计算机干货。