ThreadPoolUtil { public static boolean gracefulShutdown(@Nullable ExecutorService threadPool, int shutdownTimeoutMills) { return threadPool == null || MoreExecutors.shutdownAndAwaitTermination(threadPool, shutdownTimeoutMills, TimeUnit.MILLISECONDS); }  static boolean gracefulShutdown(@Nullable ExecutorService threadPool, int shutdownTimeoutMills); static boolean gracefulShutdown(@Nullable ExecutorService threadPool, int shutdownTimeout,
			TimeUnit timeUnit); static ThreadFactory buildThreadFactory(@NotNull String threadNamePrefix); static ThreadFactory buildThreadFactory(@NotNull String threadNamePrefix, @NotNull boolean daemon); static Runnable safeRunnable(@NotNull Runnable runnable);  }
@Test public void gracefulShutdown() throws InterruptedException { Logger logger = LoggerFactory.getLogger("test"); LogbackListAppender appender = new LogbackListAppender(); appender.addToLogger("test"); ExecutorService pool = Executors.newSingleThreadExecutor(); Runnable task = new Task(logger, 200, 0); pool.execute(task); ThreadPoolUtil.gracefulShutdown(pool, 1000, TimeUnit.MILLISECONDS); assertThat(pool.isTerminated()).isTrue(); assertThat(appender.getFirstLog()).isNull(); appender.clearLogs(); pool = Executors.newSingleThreadExecutor(); task = new Task(logger, 1000, 0); pool.execute(task); ThreadPoolUtil.gracefulShutdown(pool, 500, TimeUnit.MILLISECONDS); assertThat(pool.isTerminated()).isTrue(); assertThat(appender.getFirstLog().getMessage()).isEqualTo("InterruptedException"); appender.clearLogs(); final ExecutorService self = Executors.newSingleThreadExecutor(); task = new Task(logger, 100000, 0); self.execute(task); final CountDownLatch lock = new CountDownLatch(1); Thread thread = new Thread(new Runnable() { @Override public void run() { lock.countDown(); ThreadPoolUtil.gracefulShutdown(self, 200000, TimeUnit.MILLISECONDS); } }); thread.start(); lock.await(); thread.interrupt(); ThreadUtil.sleep(500); assertThat(appender.getFirstLog().getMessage()).isEqualTo("InterruptedException"); ThreadPoolUtil.gracefulShutdown(null, 1000); ThreadPoolUtil.gracefulShutdown(null, 1000, TimeUnit.MILLISECONDS); }