我正在开发一项返回 List<Response>
的服务目的。
有两种对象可以构建响应。其中一个从内部数据填充内容,另一个接触服务并获取数据。
for(Item item : items){
if(item is external){
call service and get result and populate Response and add to List
}
if(item is internal)
{
populate response object and add to list
}
}
当前的 impl 是程序化的和阻塞的,我想要的是一个非阻塞设计,这样,如果该项目是外部的,则触发调用并继续列表中的下一个项目。然后当循环完成时,我可以等待所有完成。
执行此操作的好方法是什么?我也在考虑为每个职责创建单独的类。
编辑:引入的原因是为了减少延迟命中。
最佳答案
ExecutorCompletionService
(带有记住提交任务的回调的线程池)看起来像一个 git 错误:
CompletionService<Response> executorService =
new ExecutorCompletionService<>(Executors.newFixedThreadPool(10));
int totalExternal = 0;
for(Item item : items){
if(item is external){
executorService.submit(externalCall(item));
++totalExternal;
}
if(item is internal){
populate response object and add to list
}
}
for (int i = 0; i < totalExternal; ++totalExternal) {
addAsynchResultToResponseList(executorService.take().get());
}
在哪里externalCall(item)
为清楚起见,定义如下:
Callable<Response> externalCall(Item item) {
return new Callable<Response>() {
//...
}
}
很明显,一旦您采用异步方式,结果列表就可以具有任意顺序。
另一种方法是使用普通的 ExecutorService
并有一个中间体 List<Future<Response>>
.诀窍是使用 AsyncResult
包装内部响应的包装器(它创建 Future
立即完成并返回传递的值)。
List<Future<Response>> futures = new ArrayList<>();
for(Item item : items){
if(item is external){
futures.add(executorService.submit(externalCall(item)));
}
if(item is internal){
futures.add(new AsyncResult(synchResponse));
}
}
现在您可以简单地遍历 futures
. AsyncResult
将立即返回,因为该值在创建时已经是计算机 ( synchResponse
)。但是你将不得不等待 Future
s 从线程池返回。
记住 Future.get()
允许您检索原始异常。同样是Future
的顺序列表中的 s 与原始项目的顺序相同,因此如果第 n 个 Future
失败,items
中的第 n 项列表是原因。
关于java - 并发 - foreach 循环中的非阻塞设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13500670/