И invoke..()
, и submit()
выполнят свои задачи немедленно (при условии наличия потоков для запуска задач). Разница в том, что invoke...()
будет ждать задач, запущенных в отдельных потоках, до конечного sh, прежде чем вернуть результат, тогда как submit()
вернется немедленно, то есть выполненная задача все еще выполняется в другой thread.
Другими словами, объекты Future
, возвращаемые из invokeAll()
, гарантированно находятся в состоянии, где Future.isDone() == true
. Future
объект, возвращаемый из submit()
, может находиться в состоянии, в котором Future.isDone() == false
.
Мы можем легко продемонстрировать разницу во времени.
public static void main(String... args) throws InterruptedException {
Callable<String> c1 = () -> { System.out.println("Hello "); return "Hello "; };
Callable<String> c2 = () -> { System.out.println("World!"); return "World!"; };
List<Callable<String>> callables = List.of(c1, c2);
ExecutorService executor = Executors.newSingleThreadExecutor();
System.out.println("Begin invokeAll...");
List<Future<String>> allFutures = executor.invokeAll(callables);
System.out.println("End invokeAll.\n");
System.out.println("Begin submit...");
List<Future<String>> submittedFutures = callables.stream().map(executor::submit).collect(toList());
System.out.println("End submit.");
}
И в результате callables
распечатать сообщение Hello World до завершения метода invokeAll()
; но callables
print Hello World после завершения метода submit()
.
/*
Begin invokeAll...
Hello
World!
End invokeAll.
Begin submit...
End submit.
Hello
World!
*/
Вы можете поиграть с этим кодом в IDE, добавив некоторое sleep()
время в c1
или c2
и смотреть, как печатает терминал. Это должно убедить вас, что invoke...()
действительно ждет, пока что-то произойдет, а submit()
- нет.