【问题标题】:Wait for every Future in a List<Future> to be done [closed]等待 List<Future> 中的每个 Future 完成[关闭]
【发布时间】:2017-12-14 06:11:37
【问题描述】:

我调用一个返回Future 的方法,为List&lt;Principal&gt; 中的每个元素调用一次,所以我最终得到一个List&lt;Future&lt;UserRecord&gt;&gt;

返回Future 的方法是库代码,我无法控制该代码的运行方式,我只有Future

我想等待所有Futures 完成(成功或失败),然后再继续。

有没有比这更好的方法:

List<Principal> users = new ArrayList<>();
// Fill users
List<Future<UserRecord>> futures = getAllTheFutures(users);
List<UserRecord> results = new ArrayList<>(futures.size());
boolean[] taskCompleted = new boolean[futures.size()];
for (int j = 0; j < taskCompleted.length; j++) {
    taskCompleted[j] = false;
}
do {
    for (int i = 0; i < futures.size(); i++) {
        if (!taskCompleted[i]) {
            try {
                results.add(i, futures.get(i).get(20, TimeUnit.MILLISECONDS));
                taskCompleted[i] = true;
            } catch (TimeoutException e) {
                // Do nothing
            } catch (InterruptedException | ExecutionException e) {
                // Handle appropriately, then...
                taskCompleted[i] = true;
            }
        }
    }
} while (allNotCompleted(taskCompleted));

对于好奇的人:

private boolean allNotCompleted(boolean[] completed) {
    for (boolean b : completed) {
        if (!b)
            return true;
    }
    return false;
}

Waiting on a list of Future 的答案不同,我无法控制创建Futures 的代码。

【问题讨论】:

  • allNotCompleted(taskCompleted)sn-p 是否检查整个数组并返回整体结果?
  • 是的,当然。
  • 你为什么在get()上使用超时?它有什么用途,因为您将不断循环回到它。此外,“适当处理”在您的上下文中意味着什么,因为它对代码需要做什么和可以做什么有很大影响。您是 Java 新手,不是吗?您将 boolean[] 初始化为 false,即使它是默认值。
  • 为什么这么复杂? for (Future&lt;UserRecord&gt; future : futures) results.add(future.get()); 怎么了?
  • @shmosel 也许是因为我只是想多了:-)。

标签: java concurrency java-8 future


【解决方案1】:

您的代码可以简化很多。除非您有未在问题中指定的要求,否则可以编写如下等效版本。

List<Principal> users = // fill users
List<Future<UserRecord>> futures = getAllTheFutures(users);
List<UserRecord> results = new ArrayList<>();

for (int i = 0; i < futures.size(); i++) {
        try {
            results.add(futures.get(i).get());
        } catch (InterruptedException | ExecutionException e) {
            // Handle appropriately, results.add(null) or just leave it out
        }
    }
}

【讨论】:

  • 因此,您唯一删除的就是获取中的等待。说得通。您错过的一件事是ith 未来的结果被添加到results 中的ith 索引中。所有的讽刺言论都是不必要的。但也许这就是你得到快乐的方式。
  • @markvgti 我真的不明白为什么你会关心索引。也许您想保留一个单独的List&lt;Principal&gt; failed,在其中添加引发failed.add(users.get(i)) 异常的期货的主体。我正在努力提供好的答案,但当有人提供不好的答案(以及那些因为不明白自己不好而支持这些不好的答案的人)时,这很难做到。
  • 事物是按顺序生成的,而且在整个链条中保持一切井井有条更容易。我很欣赏你的简单代码和你指出等待是不必要的。一旦我看到代码,我就能理解好与坏。如果我对自己的解决方案有信心,我就不会在这里寻求帮助。
  • @markvgti:for 循环按顺序遍历元素,add 将追加到列表的当前末尾,因此结果列表将与源列表的顺序相同.事实上,即使是这个答案的代码也比必要的复杂。更简单的for (Future&lt;UserRecord&gt; future : futures) try { results.add(future); } catch (…) { …} 也可以。无需处理索引。
【解决方案2】:

你可以简单地做一个简化列表;从您的列表中删除成功的响应并迭代直到为空。

List<Principal> users = // fill users
List<Future<UserRecord>> futures = getAllTheFutures(users);
List<UserRecord> results = new ArrayList<>();

for (int i = 0; i < futures.size(); i++) {
        try {
            results.add(futures.get(i).get(<how long you want before your application throws exception>));

        }
        catch (InterruptedException | ExecutionException e) {
            // Handle appropriately, results.add(null) or just leave it out
        }
        catch (TimeoutException timeoutEx) {
            // If the Future retrieval timed out you can handle here
        }

    }
}

由于您的意图是在继续之前收集“一组”作业,因此在这种情况下等到您获得线程索引 X 的返回时,将产生(大约)最后一个返回线程的时间成本。

或者,如果您计划在集合中的所有线程失败时中止,您可以使用 Java 8 CompletableFuture

CompletableFuture[] cfs = futures.toArray(new CompletableFuture[futures.size()]);

    return CompletableFuture.allOf(cfs)
            .thenApply(() -> futures.stream()
                                    .map(CompletableFuture::join)
                                    .collect(Collectors.toList())
            );
  • 感谢 Kayaman 的简化代码库。

【讨论】:

  • 不,目的是收集所有内容。它只是在问题中以一种奇怪而令人困惑的方式实现。
  • 你的代码和我的一样,只是你的代码没有做到标题所要求的,即“等待每个未来*。来吧,人们,这并不难。
  • 所以我们同意这个问题基本上没有任何意义,因为 Future 的文档解释了如何做到这一点,并且已经实现了这样做的功能。关闭问题是否应该是固执己见(除了明显简化海报的示例代码)?
  • 我在这里没有看到任何意见问题。这个问题要求一种“更好的方法来做到这一点”,我用一种更好的、惯用的方式回答。另一个答案太可怕了,你的答案一开始是错误的,但现在你无缘无故地包含了CompletableFuture
猜你喜欢
  • 2019-03-02
  • 2017-09-30
  • 1970-01-01
  • 2018-09-22
  • 2020-01-14
  • 1970-01-01
  • 2017-08-03
  • 2016-04-13
  • 1970-01-01
相关资源
最近更新 更多