From c4051a6465e0d70d119ec27c6ae4eb4d1893339a Mon Sep 17 00:00:00 2001 From: jasmine <362055143@qq.com> Date: Mon, 15 Apr 2024 03:34:56 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BA=94=E7=94=A8=E5=85=B3?= =?UTF-8?q?=E9=97=AD=EF=BC=8C=E5=85=B3=E9=97=AD=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E7=BA=BF=E7=A8=8B=E6=B1=A0ScheduledExecutorService=20*=20?= =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E7=BB=93=E6=9D=9F=EF=BC=8C=E5=85=B3=E9=97=AD?= =?UTF-8?q?ScheduledExecutorService=20=E7=BA=BF=E7=A8=8B=E6=B1=A0=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ThreadPoolAutoConfiguration.java | 68 +++++++++++++++++++ .../threadpool/ThreadPoolProperties.java | 26 +++++++ 2 files changed, 94 insertions(+) diff --git a/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java b/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java index 606143ca..0b8e1410 100644 --- a/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java +++ b/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolAutoConfiguration.java @@ -20,6 +20,7 @@ import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.ObjectUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -30,9 +31,13 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import top.continew.starter.core.constant.PropertiesConstants; import top.continew.starter.core.util.ExceptionUtils; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RunnableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; /** * 线程池自动配置 @@ -69,6 +74,11 @@ public class ThreadPoolAutoConfiguration { executor.setKeepAliveSeconds(properties.getKeepAliveSeconds()); // 配置当池内线程数已达到上限的时候,该如何处理新任务:不在新线程中执行任务,而是由调用者所在的线程来执行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + // 关闭线程池是否等待任务完成 + executor.setWaitForTasksToCompleteOnShutdown(properties.isWaitForTasksToCompleteOnShutdown()); + // 执行器在关闭时阻塞的最长毫秒数,以等待剩余任务完成执行。 + executor.setAwaitTerminationMillis(properties.getAwaitTerminationMillis()); + log.debug("[ContiNew Starter] - Auto Configuration 'ThreadPoolTaskExecutor' completed initialization."); return executor; } @@ -88,7 +98,65 @@ public class ThreadPoolAutoConfiguration { ExceptionUtils.printException(runnable, throwable); } }; + // 应用关闭时,关闭线程池 + SpringApplication.getShutdownHandlers().add(() -> { + shutdown(executor, properties); + }); log.debug("[ContiNew Starter] - Auto Configuration 'ScheduledExecutorService' completed initialization."); return executor; } + + /** + * 根据相应的配置设置关闭 ExecutorService + * + * @see org.springframework.scheduling.concurrent.ExecutorConfigurationSupport#shutdown() + */ + public void shutdown(ExecutorService executor, ThreadPoolProperties properties) { + log.debug("[ContiNew Starter] - Shutting down ScheduledExecutorService start."); + if (executor != null) { + if (properties.isWaitForTasksToCompleteOnShutdown()) { + executor.shutdown(); + } else { + for (Runnable remainingTask : executor.shutdownNow()) { + cancelRemainingTask(remainingTask); + } + } + awaitTerminationIfNecessary(executor, properties); + log.debug("[ContiNew Starter] - Shutting down ScheduledExecutorService complete."); + } + } + + /** + * Cancel the given remaining task which never commenced execution, + * as returned from {@link ExecutorService#shutdownNow()}. + * + * @param task the task to cancel (typically a {@link RunnableFuture}) + * @see RunnableFuture#cancel(boolean) + * @since 5.0.5 + */ + protected void cancelRemainingTask(Runnable task) { + if (task instanceof Future future) { + future.cancel(true); + } + } + + /** + * Wait for the executor to terminate, according to the value of the properties + */ + private void awaitTerminationIfNecessary(ExecutorService executor, ThreadPoolProperties properties) { + if (properties.getAwaitTerminationMillis() > 0) { + try { + if (!executor.awaitTermination(properties.getAwaitTerminationMillis(), TimeUnit.MILLISECONDS)) { + if (log.isWarnEnabled()) { + log.warn("[ContiNew Starter] - Timed out while waiting for executor 'ScheduledExecutorService' to terminate."); + } + } + } catch (InterruptedException ex) { + if (log.isWarnEnabled()) { + log.warn("[ContiNew Starter] - Interrupted while waiting for executor 'ScheduledExecutorService' to terminate"); + } + Thread.currentThread().interrupt(); + } + } + } } diff --git a/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java b/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java index fc36b055..5fa2114a 100644 --- a/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java +++ b/continew-starter-core/src/main/java/top/continew/starter/core/autoconfigure/threadpool/ThreadPoolProperties.java @@ -54,6 +54,16 @@ public class ThreadPoolProperties { */ private int keepAliveSeconds = 300; + /** + * 关闭线程池是否等待任务完成 + */ + private boolean waitForTasksToCompleteOnShutdown = false; + + /** + * 执行器在关闭时阻塞的最长毫秒数,以等待剩余任务完成执行。 + */ + private long awaitTerminationMillis = 0; + public boolean isEnabled() { return enabled; } @@ -93,4 +103,20 @@ public class ThreadPoolProperties { public void setKeepAliveSeconds(int keepAliveSeconds) { this.keepAliveSeconds = keepAliveSeconds; } + + public boolean isWaitForTasksToCompleteOnShutdown() { + return waitForTasksToCompleteOnShutdown; + } + + public void setWaitForTasksToCompleteOnShutdown(boolean waitForTasksToCompleteOnShutdown) { + this.waitForTasksToCompleteOnShutdown = waitForTasksToCompleteOnShutdown; + } + + public long getAwaitTerminationMillis() { + return awaitTerminationMillis; + } + + public void setAwaitTerminationMillis(long awaitTerminationMillis) { + this.awaitTerminationMillis = awaitTerminationMillis; + } }