Как выполнить задачи параллельно
Короткий ответ
ExecutorService — пул потоков, которому отдают задачи. submit() возвращает Future — «обещание» результата, а get() ждёт его:
int slowSquare(int n) throws InterruptedException {
Thread.sleep(200);
return n * n;
}
void main() throws Exception {
try (ExecutorService pool = Executors.newFixedThreadPool(3)) {
Future<Integer> a = pool.submit(() -> slowSquare(2));
Future<Integer> b = pool.submit(() -> slowSquare(3));
Future<Integer> c = pool.submit(() -> slowSquare(4));
IO.println(a.get() + b.get() + c.get());
}
}Результат:
29Три задачи по 200 мс выполняются одновременно, поэтому вся программа ждёт около 200 мс, а не 600. С Java 19 ExecutorService можно закрывать через try с ресурсами: он дождётся задач и остановит потоки.
Список задач
invokeAll() запускает все задачи и возвращает список Future в том же порядке:
void main() throws Exception {
List<Callable<String>> tasks = List.of(
() -> "report A",
() -> "report B",
() -> "report C");
try (var pool = Executors.newFixedThreadPool(2)) {
for (Future<String> future : pool.invokeAll(tasks)) {
IO.println(future.get());
}
}
}Результат:
report A
report B
report CОшибка в задаче
Исключение из задачи не теряется: get() выбрасывает ExecutionException, а исходное исключение лежит в getCause():
void main() throws InterruptedException {
try (var pool = Executors.newSingleThreadExecutor()) {
Future<Integer> future = pool.submit(() -> Integer.parseInt("oops"));
try {
future.get();
} catch (ExecutionException e) {
IO.println("Task failed: " + e.getCause().getMessage());
}
}
}Результат:
Task failed: For input string: "oops"Частая ошибка
Вызывать get() сразу после каждого submit(). Программа ждёт первую задачу, прежде чем отправить вторую, и параллельности не получается. Сначала отправьте все задачи, потом собирайте результаты.
Функции из этого ответа
- Executors.newFixedThreadPool() — Создаёт пул из заданного числа потоков.
- ExecutorService.submit() — Отправляет задачу в пул и сразу возвращает `Future` для её результата.
- Future.get() — Ждёт завершения задачи и возвращает её результат.
- ExecutorService — Сервис, который выполняет задачи в пуле потоков.