等待列表<future>中的每个Future完成

时间:2017-12-14 06:11:37

标签: java concurrency java-8 future

我为Future中的每个元素调用一个返回List<Principal>的方法,因此最终得到List<Future<UserRecord>>

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

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

有没有比这更好的方法:

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的答案不同,我无法控制创建Future的代码。

2 个答案:

答案 0 :(得分:5)

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

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));
        } catch (InterruptedException | ExecutionException e) {
            // Handle appropriately, results.add(null) or just leave it out
        }
    }
}

答案 1 :(得分: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(<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的简化代码库。