Чем shutdown() отличается от shutdownNow() у ExecutorService

Вопрос проверяет не память на два метода, а понимание жизненного цикла пула потоков. Кандидаты часто отвечают «один мягкий, другой жёсткий» и на этом останавливаются — а дальше начинается интересное.

shutdown() переводит пул в состояние SHUTDOWN: новые задачи через submit() будут отклонены с RejectedExecutionException, но все задачи, что уже стоят в очереди или выполняются, доводятся до конца. Пул завершится сам, когда очередь опустеет.

shutdownNow() ведёт себя жёстче. Он переводит пул в STOP, пытается остановить активные задачи через interrupt() и возвращает список задач, которые не успели начаться — они так и остались в очереди.

ExecutorService executor = Executors.newFixedThreadPool(4);

executor.shutdown(); if (!executor.awaitTermination( 30, TimeUnit.SECONDS)) { List dropped = executor.shutdownNow(); log.warn("Отменено задач: {}", dropped.size()); }

Ловушка в том, что shutdownNow() не гарантирует остановку. Он вызывает interrupt() у потоков, но если задача не проверяет Thread.interrupted() и не реагирует на InterruptedException, она продолжит работать до естественного конца. Спросят: что будет, если внутри задачи стоит цикл без проверки прерывания — правильный ответ: задача доработает до конца, несмотря на shutdownNow().

Паттерн из примера выше — shutdown() с таймаутом и shutdownNow() как fallback — стандартный способ гасить пул на graceful shutdown сервиса.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки