Java 8开始有个叫CompletableFuture的好东西,它能让你用很简单的写法来处理那些耗时的操作(比如查数据库或者调外部接口)。比如你可以这样写:
java
// 先查用户Bob的信息
// 查到后自动去查他的订单
// 最后把订单打印出来
CompletableFuture.supplyAsync(() -> getCustomerFromDb("Bob"))
.thenApply(c -> getOrdersForCustomer(c.id()))
.thenAccept(o -> System.out.println("Bob's orders: " + o));
但是呢,Java里很多老代码和第三方库还在用老式的Future,这玩意有两个缺点:
1. 必须手动调用get()方法才能拿到结果,而且会卡住当前线程
2. 要么就得不停地用isDone()检查任务完没完成,很麻烦
有人想了个办法把Future转成CompletableFuture:
java
public CompletableFuture toCompletableFuture(Future future) {
return CompletableFuture.supplyAsync(() -> {
try {
return future.get(); // 这里还是会卡住线程
} catch (Exception e) {
throw new CompletionException(e);
}
});
}
但这个办法只是把卡线程的问题转移了地方,还是在后台卡住了一个线程。
后来Java 21出了虚拟线程这个黑科技,这种线程特别轻量,卡住也没关系。所以我们可以这样改进:
java
public CompletableFuture toCompletableFuture(Future future) {
CompletableFuture completable = new CompletableFuture();
// 开个虚拟线程专门等着拿结果
Thread.ofVirtual().start(() -> {
try {
completable.complete(future.get());
} catch (Exception e) {
completable.completeExceptionally(e);
}
});
return completable;
}
这样既不会卡住重要线程,又不用频繁检查,完美解决了老代码和新写法之间的兼容问题。虚拟线程就像不要钱的工人,可以随便开很多个,专门用来干这种等着的工作最合适了。