1、问题描述
IDEA在运行项目,停止后,再次运行经常出现:
Error running 'Tomcat 8.5.82': Unable to open debugger port (127.0.0.1:9823): java.net.SocketException "Socket closed"
Error running 'Tomcat 8.5.82': Address localhost:1099 is already in use
尝试通过命令查看端口并没有被占用,按照网上处理类似问题无法kill
相关进程。
2、问题发现
仔细观看Stop Tomcat
按钮按下后的日志,可以发现:
12-Oct-2022 14:16:21.764 警告 [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads Web应用程序[web]似乎启动了一个名为[DefaultQuartzScheduler_QuartzSchedulerThread]的线程,但未能停止它。这很可能会造成内存泄漏。线程的堆栈跟踪:[
java.lang.Object.wait(Native Method)
2022-10-12 14:16:44.674 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG o.quartz.core.QuartzSchedulerThread:276 - batch acquisition of 0 triggers
2022-10-12 14:16:44.674 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG o.quartz.core.QuartzSchedulerThread:276 - batch acquisition of 0 triggers
...
从上面可以知道,在发出Stop
命令后,DefaultQuartzScheduler_QuartzSchedulerThread
线程未能被停止,导致一直占用相关端口。此时Stop Tomcat
按钮依旧可以点击,但是点击后并不会结束该进程!!!
仔细看了项目代码,发现是与quartz定时任务有关;其他类似关闭不了的问题相信绝大部分都是某个线程无法被关闭导致的问题,需要具体项目具体分析。
3、 问题处理
通过重写ServletContextListener
的contextDestroyed()
方法,在上下文销毁时,停止相关线程。
@WebListener
public class QuartzListener implements ServletContextListener {
private final static Logger LOGGER = LoggerFactory.getLogger(QuartzListener.class);
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
LOGGER.error("执行contextDestroyed。。。");
//停止相关线程
QuartzManager.shutdownJobs();
}
}
如果是老项目,@WebListener
注解无法使用,可以在web.xml
中手动添加监听器:
<listener>
<listener-class>xxx.xxx.xxx.QuartzListener</listener-class>
</listener>
4、 测试
正常启动后,点击Stop Tomcat
按钮后,日志如下:
2022-10-12 14:37:42.278 [main] ERROR c.c.b.core.listener.QuartzListener:43 - 执行contextDestroyed。。。
2022-10-12 14:37:42.652 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.simpl.SimpleThreadPool:612 - WorkerThread is shut down.
...
2022-10-12 14:37:43.594 [main] INFO o.s.s.c.ThreadPoolTaskScheduler:191 - Shutting down ExecutorService 'myScheduler'
再次启动,正常启动。✅