我有一个可以正常关闭Spring Boot应用程序的类。
@Configuration
public class GracefulShutdownConfig extends BaseObject {
private static Object lock = new Object();
private static boolean isPreventShutdown = false;
@Bean
public GracefulShutdown gracefulShutdown() {
return new GracefulShutdown();
}
@Bean
public ConfigurableServletWebServerFactory webServerFactory(final GracefulShutdown gracefulShutdown) {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.addConnectorCustomizers(gracefulShutdown);
return factory;
}
public class GracefulShutdown extends BaseObject
implements TomcatConnectorCustomizer, ApplicationListener<ContextClosedEvent> {
@Value("${graceful.shutdown.eureka.client.timeout}")
private long eurekaShutdownTimeout;
@Value("${graceful.shutdown.rest.controller.wait.time.max}")
private long restControllerWaitTimeMax;
@Autowired
private EurekaClient discoveryClient;
private volatile Connector connector;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
// TODO Auto-generated method stub
logger.info("onApplicationEvent ContextClosedEvent");
try {
boolean needWaitEureka = false;
synchronized (lock) {
if(!isPreventShutdown) {
needWaitEureka = true;
isPreventShutdown = true;
}
}
if(needWaitEureka) {
discoveryClient.shutdown();
Thread.sleep(eurekaShutdownTimeout);
}
this.connector.pause();
Executor executor = this.connector.getProtocolHandler().getExecutor();
if (executor instanceof ThreadPoolExecutor) {
try {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
threadPoolExecutor.shutdown();
if (!threadPoolExecutor.awaitTermination(restControllerWaitTimeMax, TimeUnit.SECONDS)) {
logger.error("Tomcat thread pool did not shut down gracefully within " + restControllerWaitTimeMax
+ " seconds. Proceeding with forceful shutdown");
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
} catch (Exception ex) {
Thread.currentThread().interrupt();
}
}
@Override
public void customize(Connector connector) {
// TODO Auto-generated method stub
this.connector = connector;
}
}
@PreDestroy
public void shutdown() {
logger.info("@PreDestroy shutdown");
Schedulers.shutdown();
Hystrix.reset();
HystrixPlugins.reset();
}
}
如果在没有任何请求的情况下启动并关闭了应用程序,则它可以正常运行。
但是,如果有使用@HystrixCommand的请求,然后关闭应用程序,它将显示错误:
2019-07-18 10:49:40.094 WARN-[35-on(4)-127.0.0.1] [] oaclWebappClassLoaderBase:Web应用程序[ROOT]似乎已启动名为[DataPublisher]的线程,但未能阻止它。这很可能造成内存泄漏。线程的堆栈跟踪: java.base / jdk.internal.misc.Unsafe.park(本机方法) java.base / java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234) java.base / java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2123) java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1182) java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) java.base / java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054) java.base / java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114) java.base / java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:628) java.base / java.lang.Thread.run(Thread.java:825)
2019-07-18 10:49:40.095 WARN-[35-on(4)-127.0.0.1] [] oaclWebappClassLoaderBase:Web应用程序[ROOT]似乎已启动名为[PollingServerListUpdater-0的线程] ],但未能阻止它。这很可能造成内存泄漏。线程的堆栈跟踪: java.base / jdk.internal.misc.Unsafe.park(本机方法) java.base / java.util.concurrent.locks.LockSupport.park(LockSupport.java:194) java.base / java.util.concurrent.locks.AbstractQueuedSynchronizer $ ConditionObject.await(AbstractQueuedSynchronizer.java:2081) java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1177) java.base / java.util.concurrent.ScheduledThreadPoolExecutor $ DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:899) java.base / java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1054) java.base / java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114) java.base / java.util.concurrent.ThreadPoolExecutor $ Worker.run(ThreadPoolExecutor.java:628) java.base / java.lang.Thread.run(Thread.java:825)
似乎是因为Hystrix线程池未成功关闭,我试图使用Hystrix.reset()但没有运气。
您能告诉我如何避免此错误吗?