Как вы ожидаете завершения всех асинхронных вызовов в Java? - PullRequest
0 голосов
/ 17 сентября 2018

Концептуально очень просто.У нас есть огромный старый Java-сайт, который не использует потоки / асинхронность.Вход в систему длится вечно, потому что он делает дюжину вызовов к различным микросервисам, но все синхронно по одному: каждый ждет завершения другого, прежде чем сделать следующий вызов.Однако ни один из вызовов API не зависит от результата любого из других.

Но нам нужно получить все результаты и объединить их, прежде чем мы продолжим.Казалось действительно очевидным, что мы должны быть в состоянии сделать эти дюжины вызовов параллельно, но ждем, пока они ВСЕ завершат, чтобы использовать свои данные В ОЧЕНЬ СЛЕДУЮЩЕМ ШАГЕ.

Так что все синхронно до и после вызовов.Однако было бы неплохо отправить их по одному параллельно, асинхронно - или просто параллельно - тогда мы ограничены только одним самым медленным вызовом, а не общим последовательным временем всех вызовов.

Я читал, что в Java 8 появился этот замечательный новый набор операций CompletableFuture.Но я нигде не нашел объяснения моего использования.Мы не хотим, чтобы результат был обещанием - мы рады подождать, пока все они завершатся, а затем продолжить.У JS есть Promise.all(), но даже это возвращает обещание.

Все, что я могу придумать, это немного подождать, когда будут сделаны асинхронные вызовы, и продолжить, только когда мы получим все результаты.Который, очевидно, чокнутый.

Я что-то здесь упускаю?Потому что это кажется таким очевидным для меня, но, похоже, ни у кого больше нет проблем с этим - иначе подход настолько прост, что никто не удосуживается спросить, и я просто не понимаю этого.

1 Ответ

0 голосов
/ 17 сентября 2018

Если я правильно понял, вы хотите что-то вроде этого:

ExecutorService executorService = Executors.newFixedThreadPool(4); // TODO: proper number of threads

Future<Integer> future1 = executorService.submit(() -> callService1()); // TODO: proper type and method
Future<String> future2 = executorService.submit(() -> callService2()); // TODO: proper type and method

executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.MINUTES); // TODO: proper timeout

Integer result1 = future1.get(); // TODO: proper type
String result2 = future2.get(); // TODO: proper type

Объяснение:

  • код выше создает ExecutorService с 4потоки, в которые вы можете отправлять все свои задачи (например, звонки на микросервисы)
  • , затем вы звоните ExecutorService.shutdown (больше не допускается отправка задач) и ExecutorService.awaitTermination (подождите, пока все задачи будут завершены)
  • наконец, вы вызываете Future.get на всех фьючерсах, чтобы получить результаты
    • обратите внимание, чтоесли задача вызвала исключение во время выполнения, вызов Future.get сгенерирует ExecutionException, который упаковывает исключение, выброшенное задачей
...