直接从CompletableFuture.thenAccept返回值

时间:2017-04-19 07:30:58

标签: java concurrency java-8 completable-future

我正在尝试从我的CompletableFuture返回一个列表:

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

它失败并出现“意外返回类型。如何以异步方式返回结果?

3 个答案:

答案 0 :(得分:6)

你的目标存在根本矛盾。您只能使用get()返回完整的,可直接使用的列表或“以异步方式返回结果”。

如果方法List<Provider> get()应该返回一个List,调用者可以无限制地使用它,它就不能保持异步操作,因为操作必须在{{{{}时完成1}}返回。这可以像调用get()一样简单,等待完成并获得结果:

join()

或只是

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

这有效地将public List<Provider> get() { return getSomeData().join(); } 的潜在异步操作转换为同步操作。

This answer,使用

getSomeData()

不等待操作完成,但在安排public List<Provider> get() { List<Provider> providers = new ArrayList<>(); CompletableFuture<List<Provider>> providersResponse = getSomeData(); providersResponse.thenAccept(providers::addAll); return providers; } 操作后返回一个新的ArrayList,该操作的执行完全不受此方法的控制。

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

当您使用线程安全ArrayList实现修复该代码时,仍然会遇到以下问题:返回的List在查询时可能为空,并且在任何时间点之外的任意时间点填充来电者的控制权。这是不可修复的,正如开头所说,这是想要异步操作但返回List的基本问题。

List已经是潜在异步操作的封装,因此如果您希望操作保持异步,只需将CompletableFuture返回给调用者,以便获得控制权。否则,如果您希望调用者接收可以无限制使用的CompletableFuture<List<Provider>>,请在返回结果之前等待完成,例如通过List

答案 1 :(得分:1)

试试这个:

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

答案 2 :(得分:0)

试试这个:

[('Date', 'Wed, 19 Apr 2017 13:48:41 GMT'),
('Content-Type', 'application/octet-stream; charset=UTF-8'),
('Content-Disposition', 'attachment;filename=filename.csv.gz'),
('Content-Length', '2117014'),
('Server', 'Jetty(9.2.17.v20160517)')]