Как заставить ScheduledExecutorService автоматически завершать работу при отмене запланированной задачи


Я использую ScheduledExecutorService для закрытия сетевого соединения, если оно было открыто более нескольких часов. Однако в большинстве случаев сетевое соединение закрывается до истечения тайм-аута, поэтому я отменяю ScheduledFuture. В этом случае я также хочу, чтобы служба executor завершила работу и освободила свой пул потоков.

К моему удивлению, это не работает из коробки: хотя я вызвал shutdown() на службу исполнителя после планирования задачи, служба исполнителя не завершается автоматически, когда его единственная запланированная задача отменяется. Из JavaDoc ExecutorService.shutdown() это поведение может быть даже правильным, потому что, возможно, отмененная задача не была "выполнена":

Пустота java.утиль.параллельный.ExecutorService.выключение()

Инициирует упорядоченное завершение работы, при котором выполняются ранее представленные задачи, но новые задачи не принимаются. Вызов не имеет никакого дополнительного эффекта, если он уже выключен.

Мой вопрос в том, может ли это быть изменено: можно ли настроить службу исполнителя на автоматическое завершение работы при отмене единственной запланированной задачи?


Или тот же вопрос, написанный как тест JUnit:

@Test
public void testExecutorServiceTerminatesWhenScheduledTaskIsCanceled() throws Exception {
    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    Runnable task = new Runnable() {
        @Override
        public void run() {
            // ...
        }
    };

    ScheduledFuture<?> scheduledTask = scheduler.schedule(task, 2000, TimeUnit.MILLISECONDS);
    scheduler.shutdown();
    // do more configuration here...

    Thread.sleep(1000);

    scheduledTask.cancel(false);

    Thread.sleep(100);
    assertThat(scheduler.isTerminated(), is(true)); // ... so that this passes!?
}
1 4

1 ответ:

Из документации ScheduledThreadPoolExecutor (фактический тип, возвращаемый Executors.newScheduledThreadPool):

Когда отправленная задача отменяется до ее запуска, выполнение подавляется. По умолчанию такая отмененная задача не удаляется автоматически из рабочей очереди до истечения ее задержки. Хотя это позволяет проводить дальнейшие проверки и мониторинг, это также может привести к неограниченному удержанию отмененных заданий. Чтобы избежать этого, установите setRemoveOnCancelPolicy (boolean) в true, что приведет к немедленному удалению задач из рабочей очереди в момент отмены заказа.

Однако это метод ScheduledThreadPoolExecutor. Я не верю, что это возможно решить чисто с помощью интерфейса ScheduledExecutorService.