Как выполнить две задачи параллельно
Два Thread
Низкоуровневый вариант сохраняет идею исходной заметки:
Thread first = new Thread(this::loadUsers, "users-loader");
Thread second = new Thread(this::loadOrders, "orders-loader");
first.start();
second.start();
first.join();
second.join();start() обоих потоков вызывается до join(). Если написать first.start(); first.join(); second.start(), задачи будут выполняться последовательно.
ExecutorService
В прикладном коде пул обычно безопаснее неограниченного создания потоков:
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
Future<UserData> users = pool.submit(this::loadUsers);
Future<OrderData> orders = pool.submit(this::loadOrders);
Report report = combine(users.get(), orders.get());
} finally {
pool.shutdown();
}Ошибку задачи get() вернет как ExecutionException, а прерывание ожидающего потока — как InterruptedException.
CompletableFuture
Для композиции независимых результатов:
CompletableFuture<UserData> users =
CompletableFuture.supplyAsync(this::loadUsers, ioPool);
CompletableFuture<OrderData> orders =
CompletableFuture.supplyAsync(this::loadOrders, ioPool);
CompletableFuture<Report> report =
users.thenCombine(orders, this::combine);Исполнитель лучше передавать явно: общий пул может одновременно обслуживать чужие parallel streams и CPU-задачи.
Ограничения
- Параллелить можно только независимые операции.
- Общие изменяемые данные требуют синхронизации или устранения совместного владения.
- Две операции по 100 мс не гарантируют ответ за 100 мс: есть очереди, CPU, сеть и сборка результата.
- При сбое одной ветки нужно определить отмену второй и общий deadline.
- Для внешнего ресурса важен его лимит: 100 потоков не создадут 100 соединений, если пул БД равен 10.
На собеседовании
- Где поставить
join()? После запуска обеих задач. - Чем пул лучше
new Threadна каждый вызов? Ограничивает ресурсы и переиспользует потоки. - Когда параллельность замедляет? Для мелких задач или при общем узком ресурсе.
- Как получить два результата? Два
FutureлибоthenCombine. - Что делать с общим тайм-аутом? Считать единый deadline, а не давать каждой ветке полный timeout.