java - 如何确保 CompletableFuture 在执行一段代码之前完全完成?
问题描述
我有这段代码,我有两个问题。
- 我不确定为什么我会看到 TimeoutException,因为任何地方都没有阻塞。
- 我想要实现的
Collector
是我有一个类将进入收集一堆指标,并且在CompletableFuture
完全完成之后我将执行Collector
以发布指标。finally
保证它会最后执行,因为我认为应该.get()
被阻止直到它完成?
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Supplier;
public class FutureWithCollector
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
Collector collector = new Collector();
finalize(() -> query(collector), collector);
}
private static void finalize(Supplier<CompletableFuture<String>> submission, Collector collector) throws ExecutionException, InterruptedException
{
ExecutorService executorService = Executors.newFixedThreadPool(1);
CompletableFuture<String> s = CompletableFuture.supplyAsync(submission, executorService).thenCompose(Function.identity());
try {
String result = s.get(1000, TimeUnit.MILLISECONDS);
System.out.println(result);
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
System.out.println(collector.getI());
}
}
private static CompletableFuture<String> query(Collector collector)
{
CompletableFuture<String> future = new CompletableFuture<>();
return future.thenApply(r -> {
collector.collectStuff();
return "Hello";
});
}
}
class Collector
{
private volatile int i;
public void collectStuff()
{
i++;
}
public int getI()
{
return i;
}
}
输出
java.util.concurrent.TimeoutException
at java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1771)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1915)
at FutureWithCollector.finalize(FutureWithCollector.java:23)
at FutureWithCollector.main(FutureWithCollector.java:15)
0
解决方案
这很简单,只需更改您的一种方法:
private static CompletableFuture<String> query(Collector collector) {
return CompletableFuture.supplyAsync(() -> {
collector.collectStuff();
return "hello";
});
}
你正在做:
CompletableFuture<String> future = new CompletableFuture<>();
记录为:
创建一个新的不完整的CompletableFuture。
本质上,没有人完成这个CompletableFuture
,所以你总是会得到一个超时,不管它有多大。
您也可以稍微更改您的代码。如果您想要run
某事,请明确地说:
private static CompletableFuture<Void> query(Collector collector) {
return CompletableFuture.runAsync(collector::collectStuff);
}
然后请注意collectStuff
增量 a volatile
,但这些增量不是原子的。
而且您始终可以使用join
而get
不是处理已检查的异常(join
假设没有超时)。
推荐阅读
- django - 如何使用django-ckeditor为不同的模型指定不同的图片上传路径?
- python - 当 C++ 程序正在读取文件而单独的 python GUI 脚本正在写入同一文件时,会发生分段错误
- jquery - 让两个奇怪大小的元素响应地位于想象容器的中心和边缘
- c# - 如何使用从抽象类继承的字段为每个实体创建一个额外的表
- google-apps-script - 检查一个单元格的值,相应地更改另一个单元格的值,以及发送电子邮件
- php - 使用 PHP 登录后将用户重定向到上一页
- java - 接收短信无反应,BroadcastReceiver
- javascript - 如何在许多页面使用的模板中实现没有重定向的内容实验
- swift - “-c”选项对 Swift 编译器 (swiftc) 有什么作用?
- gmail - Apache JAMES:Gmail 说从我的服务器发送的电子邮件未经过 TLS 加密