Java: как правильно остановить потоки при перезапуске Tomcat

Моя проблема: каждый раз, когда я перезапускаю 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)

Такая же ситуация и с каждым отдельным потоком. Итак, есть два вопроса:

  1. Как правильно отменить регистрацию драйвера JDBC?
  2. Возможно ли, что ошибки с закрытием потока являются причиной медленного перезапуска Tomcat? Если да, то как правильно закрыть каждый поток?

Я пытался вставить следующий код внутрь каждого потока, но при каждом перезапуске наблюдаются одни и те же исключения:

if (Thread.currentThread().isInterrupted())
     {
         throw new InterruptedException();
     }

Я использую Java 8 и Tomcat-9.

Я очень ценю любую помощь! Заранее спасибо!

Используйте прослушиватель контекста сервлета для управления жизненным циклом внутренних компонентов, используемых каждым контекстом.

DuncG 28.07.2024 13:26

@DuncG Спасибо за ответ! Правильно ли я понимаю, что все потоки должны быть завершены (а также должна быть отменена регистрация драйвера JDBC) в методе contextDestroyed()? Меня смущает тот факт, что согласно документации Oracle по методу contextDestroyed() «Все сервлеты и фильтры будут уничтожены до того, как какие-либо ServletContextListeners будут уведомлены об уничтожении контекста». Насколько я понимаю, все потоки должны быть закрыты и другие действия должны быть выполнены до вызова этого метода.

Whatever22 28.07.2024 13:44

Уничтожьте свои сервлеты перед контекстом.

DuncG 28.07.2024 16:09
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
66
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

вр; доктор

Нет, ваши собственные потоки не очищаются за вас, если вы не используете Jakarta Concurrency.

Почистите свои темы

Если вы запускаете какие-либо службы-исполнители, потоки или таймеры из своего сервлета, вам необходимо закрыть их до выхода из веб-приложения. Если вы пренебрегаете этим, поддерживающие потоки могут продолжать работать бесконечно, как зомби 🧟‍♂️.

Подключитесь к жизненному циклу веб-приложения

Вы можете запускать код, когда ваше веб-приложение, ваш «контекст», запускается и заканчивается. Напишите класс, реализующий ServletContextListener , и добавьте аннотацию с помощью @WebListener.

Избегайте Timer/TimerTask

Остерегайтесь: Timer и TimerTask были давно вытеснены платформой Executors, добавленной в Java 5, как отмечено в Javadoc.

Джакартский параллелизм

Лучшее решение — перейти на контейнер сервлетов, поддерживающий Jakarta Concurrency, вместо того, чтобы открывать свои собственные службы-исполнители, потоки или таймеры. Такой контейнер сервлетов автоматически очистит все потоки, управляемые от вашего имени.

У вас есть выбор из множества таких контейнеров, включая некоторые версии Apache TomEE (построенного на базе Tomcat).


Найдите, чтобы узнать больше. Эти темы уже много раз обсуждались на Stack Overflow.

Другие вопросы по теме