Parar timer programado quando o desligamento tomcat

Eu tenho um arquivo WAR implantado no servidor Tomcat, uma das classs será chamada no momento da boot e, em seguida, o método init () programará um timer para triggersr a cada 5 horas para executar algumas tarefas.

Meu código init () se parece com isto:

public void init() { TimerTask parserTimerTask = new TimerTask() { @Override public void run() { XmlParser.parsePage(); } }; Timer parserTimer = new Timer(); parserTimer.scheduleAtFixedRate(parserTimerTask, 0, PERIOD); } 

Meu aplicativo é executado sem problemas, mas quando eu desligar o Tomcat usando /etc/init.d/tomcat7 stop , então eu verificar o log (catalina.out) tem uma input como esta:

GRAVE: O aplicativo da web [/ MyApplication] parece ter iniciado um segmento chamado [Timer-0], mas não conseguiu pará-lo. Isso provavelmente causará uma perda de memory.

Eu entendo isso é causado por mim agendar o timer, mas a minha pergunta é:

  1. Eu não defini o setDeamon como true, então o timer não deve impedir o Tomcat de desligar, em vez de deixá-lo em execução?
  2. Posso, no meu aplicativo, detectar o Tomcat vai ser desligado e cancelar meu timer?
  3. Quais são as outras soluções que posso usar para cuidar desse problema?

Obrigado!

ATUALIZAR

Mudei meu código para o seguinte com base em alguma pesquisa e na resposta de DaveHowes.

 Timer parserTimer; TimerTask parserTimerTask; public void init() { parserTimerTask = new TimerTask() { @Override public void run() { XmlParser.parsePage(); } }; parserTimer = new Timer(); parserTimer.scheduleAtFixedRate(parserTimerTask, 0, PERIOD); } @Override public void contextDestroyed(ServletContextEvent arg0) { Logger logger = Logger.getRootLogger(); logger.info("DETECT TOMCAT SERVER IS GOING TO SHUT DOWN"); logger.info("CANCEL TIMER TASK AND TIMER"); otsParserTimerTask.cancel(); otsParserTimer.cancel(); logger.info("CANCELING COMPLETE"); } @Override public void contextInitialized(ServletContextEvent arg0) { } 

Agora minha nova pergunta:

  1. Eu cancelo o TimerTask primeiro e depois o Timer, está correto?
  2. Há outra coisa que devo fazer?

Obrigado!

ATUALIZAR

Não funciona Eu coloquei algumas instruções de log no método contextDestroyed (), depois de desligar o Tomcat, o arquivo de log só tem o seguinte:

PowderGodAppWebService -> [07 fev 2012 04:09:46 PM] INFO (PowderGodAppWebService.java:45) :: DETECTAR SERVIDOR TOMCAT ESTÁ INICIANDO PowderGodAppWebService -> [07 fev 2012 04:09:46 PM] INFO (PowderGodAppWebService. java: 46) :: CANCELAR TEMPORIZADOR E TEMPORIZADOR

CANCELAMENTO COMPLETO não está lá.

Também verifiquei processos em execução (não sou especialista em Linux, portanto, uso o Activity Monitor do Mac.

  • Certifique-se de que nenhum processo java esteja em execução
  • Inicie o Tomcat, observe o PID desse processo java
  • Pare o Tomcat
  • Encontrado o processo Tomcat desapareceu
  • Inicie o Tomcat, observe o PID desse processo java
  • Implantar meu arquivo war
  • Experimente o processo, veja o tópico [Timer-0] está lá
  • Tomcat de desligamento
  • Descobriu que o processo ainda está lá
  • Experimente o processo
  • Veja [Timer-0] ainda está lá

FIXO

Eu mudei meu código para parserTimer = new Timer(true); para que meu timer seja executado como um encadeamento do daemon porque o contextDestroyed() é chamado depois que o Tomcat é encerrado.

“Todos os servlets e filtros serão destruídos antes que qualquer ServletContextListeners seja notificado da destruição do contexto.”

http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html

Não use o Timer em um ambiente Java EE! Se a tarefa lançar uma exceção de tempo de execução, todo o Timer será eliminado e não será mais executado. Você basicamente precisa reiniciar o servidor inteiro para que ele seja executado novamente. Além disso, é sensível a alterações no relógio do sistema.

Use ScheduledExecutorService lugar. Não é sensível a exceções lançadas em tarefas nem a alterações no relógio do sistema. Você pode desligá-lo pelo seu método shutdownNow() .

Aqui está um exemplo de como toda a implementação de ServletContextListener pode parecer (note: nenhum registro em web.xml requerido graças à nova anotação de @WebListener ):

 @WebListener public class BackgroundJobManager implements ServletContextListener { private ScheduledExecutorService scheduler; @Override public void contextInitialized(ServletContextEvent event) { scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(new YourParsingJob(), 0, 5, TimeUnit.HOUR); } @Override public void contextDestroyed(ServletContextEvent event) { scheduler.shutdownNow(); } } 

O método de destruição de servlets é chamado porque o servlet está prestes a ser descarregado. Você pode cancelar o cronômetro de lá, desde que você altere o escopo do próprio parserTimer para torná-lo uma variável de instância. Eu não vejo um problema com isso desde que você o acesse somente a partir do init e destrua.

O mecanismo de servlet está livre para descarregar o servlet sempre que achar conveniente, mas na prática eu só o vejo chamado quando o mecanismo de servlet é interrompido – outras pessoas podem ter outras experiências disso, embora possam provar que estou errado.

Tente usar o framework para agendamento.

Se você adaptar o Spring Framework, poderá usar os resources de construção nos agendamentos.

Ao agendar com o Spring, nunca tive nenhum problema ao parar o servidor de aplicativos.

Coloque parseTimer.purge () no seu onContetexyDestroyed. Ele removerá todos os timers da fila, se existirem.