Моя проблема: каждый раз, когда я перезапускаю Tomcat как службу (через Services.msc в Windows), этот процесс занимает много времени (около 2 минут). В журналах Tomcat (tomcat9-stderr.yyyy-mm-dd.txt) я вижу, что все потоки не могут быть правильно остановлены, и, кроме того, существует проблема с отменой регистрации драйвера JDBC:
26-Jul-2024 15:32:16.575 WARNING [Thread-9] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [MyWebApp] registered the JDBC driver [net.sourceforge.jtds.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
26-Jul-2024 15:32:16.575 WARNING [Thread-9] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [MyWebApp] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Unknown Source)
java.util.TimerThread.mainLoop(Unknown Source)
java.util.TimerThread.run(Unknown Source)
Такая же ситуация и с каждым отдельным потоком. Итак, есть два вопроса:
Я пытался вставить следующий код внутрь каждого потока, но при каждом перезапуске наблюдаются одни и те же исключения:
if (Thread.currentThread().isInterrupted())
{
throw new InterruptedException();
}
Я использую Java 8 и Tomcat-9.
Я очень ценю любую помощь! Заранее спасибо!
@DuncG Спасибо за ответ! Правильно ли я понимаю, что все потоки должны быть завершены (а также должна быть отменена регистрация драйвера JDBC) в методе contextDestroyed()? Меня смущает тот факт, что согласно документации Oracle по методу contextDestroyed() «Все сервлеты и фильтры будут уничтожены до того, как какие-либо ServletContextListeners будут уведомлены об уничтожении контекста». Насколько я понимаю, все потоки должны быть закрыты и другие действия должны быть выполнены до вызова этого метода.
Уничтожьте свои сервлеты перед контекстом.
Нет, ваши собственные потоки не очищаются за вас, если вы не используете Jakarta Concurrency.
Если вы запускаете какие-либо службы-исполнители, потоки или таймеры из своего сервлета, вам необходимо закрыть их до выхода из веб-приложения. Если вы пренебрегаете этим, поддерживающие потоки могут продолжать работать бесконечно, как зомби 🧟♂️.
Вы можете запускать код, когда ваше веб-приложение, ваш «контекст», запускается и заканчивается. Напишите класс, реализующий ServletContextListener , и добавьте аннотацию с помощью @WebListener.
Timer
/TimerTask
Остерегайтесь: Timer
и TimerTask
были давно вытеснены платформой Executors, добавленной в Java 5, как отмечено в Javadoc.
Лучшее решение — перейти на контейнер сервлетов, поддерживающий Jakarta Concurrency, вместо того, чтобы открывать свои собственные службы-исполнители, потоки или таймеры. Такой контейнер сервлетов автоматически очистит все потоки, управляемые от вашего имени.
У вас есть выбор из множества таких контейнеров, включая некоторые версии Apache TomEE (построенного на базе Tomcat).
Найдите, чтобы узнать больше. Эти темы уже много раз обсуждались на Stack Overflow.
Используйте прослушиватель контекста сервлета для управления жизненным циклом внутренних компонентов, используемых каждым контекстом.