Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как выполнить задачи параллельно

Короткий ответ

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 — Сервис, который выполняет задачи в пуле потоков.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.