Завершение работы пула в Java
При выходе из приложения фоновые потоки не должны висеть бесконечно и мешать завершению JVM. Пул нужно явно перевести в режим приёма только уже стоящих задач или прервать их, а затем дождаться освобождения ресурсов.
shutdown() перестаёт принимать новые поручения,
но уже поставленные задачи дорабатывают. shutdownNow()
пытается остановить всё сразу и возвращает список задач,
которые не успели стартовать:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(1);
pool.execute(() -> System.out.println("queued"));
pool.shutdown();
boolean finished = pool.awaitTermination(2, TimeUnit.SECONDS);
System.out.println(finished);
}
}
awaitTermination возвращает true, если
пул успел закрыться до таймаута. Без этого вызова
shutdown() только объявляет намерение: рабочие
потоки могут ещё некоторое время оставаться живыми.
Начиная с Java 19 ExecutorService реализует
AutoCloseable: блок try-with-resources
вызывает close(), который по сути выполняет
shutdown и ждёт завершения:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
try (ExecutorService pool = Executors.newFixedThreadPool(2)) {
pool.execute(() -> System.out.println("inside"));
}
}
}
Такой стиль удобен в Java 27 для локальных пулов внутри
одного метода: не нужно дублировать shutdown
и awaitTermination в finally.
Откройте пул, поставьте задачу с паузой
100 мс и убедитесь, что сообщение
успевает напечататься до закрытия пула.