java 等待 List<Future> 中的每个 Future 完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47806925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 09:49:17  来源:igfitidea点击:

Wait for every Future in a List<Future> to be done

javaconcurrencyjava-8future

提问by markvgti

I call a method that returns a Future, once for each element in a List<Principal>, so I end up with a List<Future<UserRecord>>.

我调用了一个返回 a 的方法,为 aFuture中的每个元素调用一次List<Principal>,所以我最终得到了 a List<Future<UserRecord>>

The method returning Futureis library code and I have no control over how that code gets run, all I have is the Future.

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

I want to wait for all the Futures to finish (success or failure) before proceeding further.

我想Future在继续之前等待所有s 完成(成功或失败)。

Is there a better way to do so than this:

有没有比这更好的方法:

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));

For the curious:

对于好奇:

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

Unlike in this answer to Waiting on a list of FutureI don't have control over the code that creates the Futures.

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

回答by Kayaman

Your code can be simplified a lot. An equivalent version could be written as follows, unless you have requirements that you didn't specify in the question.

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

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
        }
    }
}

回答by Elysiumplain

You could simply do a reductive list; removing successful responses from your list and iterating until empty.

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

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
        }

    }
}

Since your intent is to collect a "set" of Jobs before progressing, waiting until you get a return on thread index X in this case will give a time cost of (roughly) the last returned thread.

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

Or, if you plan to abort all threads in the set if any fail, you can use Java 8 CompletableFuture

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

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

    return CompletableFuture.allOf(cfs)
            .thenApply(() -> futures.stream()
                                    .map(CompletableFuture::join)
                                    .collect(Collectors.toList())
            );
  • credit to Kayaman for simplified code base.
  • 感谢 Kayaman 简化了代码库。