когда я вызываю get для элемента uglyList, выполнение блокируется до тех пор, пока не будет просмотрен весь список (переданный в качестве параметра для вызываемого объекта) и все CompletableFutures будут вставлены в карту, верно?
Да, это правильно. get()
будет ожидать завершения Callable
, что в вашем случае означает конец метода CallableC#call()
, который будет достигнут в конце цикла for, когда все CompletableFutures
созданы ивставлен в futureMap
, независимо от состояния / завершения этих CompletableFuture
с.
возможно, что get в этом примере также ожидает завершения CompletableFutures на карте?
Этого можно достичь, но не без дополнительного кода.
Минимальный способ сделать это в вашем коде - добавить вызов соединения внутри CompletableFuture
s. Задачи.
@Override
public Map<String, CompletableFuture<String>> call() throws Exception {
for (int j = 0; j < listString.size(); ++j) {
CompletableFuture<String> future = someMethod();
futureMap.put(listString.get(j), future);
}
// This will wait for all the futures inside the map to terminate
try {
CompletableFuture.allOf(futureMap.values().toArray(new CompletableFuture[0])).join();
} catch (CompletionException e) {
// ignored - the status will be checked later on
}
return futureMap;
}
Другим способом было бы подождать в самом конце (я пропускаю обработку исключений для краткости):
for (int i = 0; i < coresNumber; ++i) {
threads.add(executor.submit(new CallableC(splittedList.get(i),)));
}
// This will wait for all the futures to terminate (thanks to f.get())
// And then, all the completable futures will be added to an array of futures that will also be waited upon
CompletableFuture.allOf(
uglyList.stream().flatMap(f -> f.get().values().stream()).toArray(CompletableFuture[]::new)
).join();
Но если это возможно для вас, я бы упростилвесь код, используя только завершаемые фьючерсы, если только у вас нет веских оснований ломать задачи так, как вы делаете (используя список, выделенного исполнителя и т. д.). Это может выглядеть так (возможно, несколько опечаток)
List<String> items = ...
ConcurrentMap<String, String> resultsByItem = new ConcurrentHashMap<>();
Future<Void> allWork = CompletableFuture.allOf(
items.stream()
.map(item -> someWork(item) // Get a completable future for this item
.andThen(result -> resultsByItem.put(item, result)) // Append the result to the map
).toArray(CompletableFuture[]::new)
);
allWork.join();
// Your futureMap is completed.
Это заменит ваш весь код в вопросе.