Чем 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 — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки