ExecutorServiceUtils { public void gracefulShutdown(final ExecutorService service, final Duration timeout) throws InterruptedException { service.shutdown(); final long timeout_in_unit_of_miliseconds = timeout.toMillis(); if (!service.awaitTermination(timeout_in_unit_of_miliseconds, MILLI_SECONDS_TIME_UNIT)) { service.shutdownNow(); if (!service.awaitTermination(timeout_in_unit_of_miliseconds, MILLI_SECONDS_TIME_UNIT)) { logger.error("The executor service did not terminate."); } } }  void gracefulShutdown(final ExecutorService service, final Duration timeout);  }
@Test public void gracefulShutdown() throws InterruptedException { final ExecutorService service = Executors.newSingleThreadExecutor(); this.executorServiceUtils.gracefulShutdown(service, Duration.ofMillis(1)); assertThat(service.isShutdown()).isTrue(); }
@Test public void force_shutdown_after_timeout() throws InterruptedException { final ExecutorService service = mock(ExecutorService.class); when(service.awaitTermination(1, TimeUnit.MILLISECONDS)).thenReturn(false); this.executorServiceUtils.gracefulShutdown(service, Duration.ofMillis(1)); verify(service).shutdown(); verify(service).shutdownNow(); }
@Test public void can_not_submit_tasks_after_shutdown() throws InterruptedException { final ExecutorService service = Executors.newSingleThreadExecutor(); service.submit(this::sleep); this.executorServiceUtils.gracefulShutdown(service, Duration.ofMillis(1)); final Throwable thrown = catchThrowable(() -> service.submit(this::sleep)); assertThat(thrown).isInstanceOf(RejectedExecutionException.class); }