Return 值直接来自 CompletableFuture.thenAccept

Return value directly from CompletableFuture.thenAccept

我正在尝试 return 我的 CompletableFuture 中的列表,如下所示:

public List<Provider> get() {
    CompletableFuture<List<Provider>> providersResponse = getSomeData();
    return providersResponse.thenAccept((List<Provider> providers) -> {
        return providers;
    });
}

它失败了,但出现了“意外的 return 类型。我怎样才能 return 以异步方式得到结果?

试试这个:

public List<Provider> get() {
    List<Provider> providers = Collections.synchronizedList(new ArrayList<>());
    CompletableFuture<List<Provider>> providersResponse = getSomeData();
    providersResponse.thenAccept(providers::addAll);
    return providers;
}

试试这个:

public List<Provider> get() {
    return getSomeData().get();
}

您的目标存在根本矛盾。您只能拥有 get() return 一个完整的、直接可用的列表或“return 异步方式的结果”。

如果方法 List<Provider> get() 应该 return 一个 List 可以被调用者无限制地使用,它不能保持异步操作,因为操作必须已在 get() return 秒时完成。这个可以很简单的实现,调用join(),等待完成,得到结果:

public List<Provider> get() {
    CompletableFuture<List<Provider>> providersResponse = getSomeData();
    return providersResponse.join();
}

或者只是

public List<Provider> get() {
    return getSomeData().join();
}

这有效地将 getSomeData() 的潜在异步操作转变为同步操作。

,使用

public List<Provider> get() {
    List<Provider> providers = new ArrayList<>();
    CompletableFuture<List<Provider>> providersResponse = getSomeData();
    providersResponse.thenAccept(providers::addAll);
    return providers;
}

不等待操作完成,而是 return 在调度 addAll 操作之后新的 ArrayList,其执行完全不受此方法的控制。

这是一个异步操作,所以当 get() returns 时,List 可能仍然是空的,但稍后会被任意线程更新。由于 ArrayList 不是线程安全的,因此感知状态不必是空的或已完成的,它可以是任意的中间状态,甚至不需要保持一致。使用该代码时,请为奇怪的异常、看似不可能的情况或其他意外情况做好准备。

当您使用线程安全 List 实现修复该代码时,您仍然会遇到 returned List 在查询时可能为空并在调用者控制之外的任意时间点。这是不可修复的,如开头所说,这是想要异步操作但 returning List.

的根本问题

CompletableFuture 已经是一个潜在异步操作的封装,所以如果你想让操作保持异步,只需 return 将 CompletableFuture<List<Provider>> 给调用者,以允许获得控制权。否则,如果您希望调用者收到可以不受限制地使用的 List,请在 returning 结果之前等待完成,例如通过 join().