Tomcat не может остановить поток в веб-приложении
В моем веб-приложении у меня есть 3 потока, в которых tomcat не может остановить 2 из них при перезагрузке.
SEVERE: веб-приложение [/myapp], похоже, запустило поток с именем [Thread-8], но не смогло его остановить. Это очень вероятно, чтобы создать утечку памяти. май 08, 2013 11:22:40 org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
Это приводит к увеличению загрузки процессора при каждой перезагрузке.
Вот один из потоков, который tomcat не может остановить:
Часть кода, реализованного в моем ServletContextListener:
public void contextInitialized(ServletContextEvent event)
{
final UpdaterThread updaterThread = new UpdaterThread();
updaterThread.start();
event.getServletContext().setAttribute("updaterthread", updaterThread);
}
public void contextDestroyed(ServletContextEvent event)
{
UpdaterThread updaterThread = (UpdaterThread) event.getServletContext().getAttribute("updaterthread");
if (updaterThread != null)
{
updaterThread.stopUpdater();
updaterThread.interrupt();
updaterThread = null;
}
}
И важные части UpdaterThread:
public class UpdaterThread extends Thread implements Runnable
{
private boolean alive = true;
@Override
public void run()
{
while(true)
{
try
{
while (alive)
{
doUpdate();
sleep(60*1000);
}
}
catch (InterruptedException ie) {}
catch (Exception e) {}
}
}
public void stopUpdater()
{
alive = false;
}
}
У кого-нибудь есть идеи, почему эта тема не останавливается? Есть ли лучший способ реализовать поток, выполняющий некоторую работу в определенное время?
3 ответа
Насколько я вижу, вы на самом деле не останавливаете свою нить вообще. У вас есть два while
петли, и вы останавливаете только внутренний, когда вы установите alive = false
, Внешнее будет работать вечно, ничего не делая. Вы также не справляетесь с interrupt
ваша отправка, так что это не приведет к прекращению потока.
Я бы вместо этого сделал что-то вроде этого:
public void run()
{
while(alive)
{
try
{
doUpdate();
sleep(60*1000);
}
catch (InterruptedException ie) {
alive = false;
}
}
}
Кроме того, если вы дадите своему потоку правильное имя при создании, вы увидите, действительно ли этот поток вызывает проблему, о которой сообщает Tomcat.
это связано с проблемами ThreadLocal с tomcat, проверьте этот документ http://wiki.apache.org/tomcat/MemoryLeakProtection
16 марта 2010 г. 11:47:24 org.apache.catalina.loader.WebappClassLoader clearThreadLocalMap SEVERE: веб-приложение создало ThreadLocal с ключом типа [test.MyThreadLocal] (значение [test.MyThreadLocal@4dbb9a58]) и значением типа [test.MyCounter] (значение [test.MyCounter@57922f46]), но не удалось удалить его при остановке веб-приложения. Чтобы предотвратить утечку памяти, ThreadLocal был принудительно удален.
http://forum.springsource.org/showthread.php?84202-Installation-ThreadLocal-forcefully-removed
Небольшое изменение в вашем коде, чтобы исправить эту проблему
public class UpdaterThread extends Thread implements Runnable
{
private boolean alive = true;
@Override
public void run()
{
while(alive)
{
try
{
doUpdate();
sleep(60*1000);
}
catch (InterruptedException ie) {
//sleep interrupted
}
catch (Exception e) {
// exception in doUpdate method ? must handle this
}
}
}
public void stopUpdater()
{
alive = false;
}
}
Тем не мение, Sleep
в цикле while может возникнуть проблема с производительностью. Вы могли бы использовать Thread.sleep
только если вы хотите приостановить вашу ветку на некоторое время. Не используйте его, если хотите дождаться какого-то состояния.
Проверьте этот вопрос SO: Thread-sleep-call-in-loop