你的目标存在根本的矛盾。你只能拥有其中一个,get()
返回一个完整的、可直接使用的列表或“以异步方式返回结果”。
如果方法List<Provider> get()
应该返回一个List
调用者可以不受限制地使用它,它不能保持异步操作,因为该操作必须在以下时间完成:get()
返回。这可以通过简单的调用来实现join()
,等待完成并得到结果:
public List<Provider> get() {
CompletableFuture<List<Provider>> providersResponse = getSomeData();
return providersResponse.join();
}
or just
public List<Provider> get() {
return getSomeData().join();
}
这有效地改变了潜在的异步操作getSomeData()
进入同步操作。
这个答案, using
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
.
The CompletableFuture
已经是对潜在异步操作的封装,因此如果您希望操作保持异步,只需返回CompletableFuture<List<Provider>>
给调用者,以允许获得控制权。否则,如果您希望呼叫者收到List
可以不受限制地使用,等待完成后再返回结果,例如通过join()
.