2012-02-07 60 views
20

我有一個WAR文件部署到Tomcat服務器,其中一個類將在啓動時被調用,然後init()方法將計劃一個計時器每5小時執行一次任務。關閉tomcat時停止計劃的定時器

我的init()的代碼如下所示:

public void init() 
{ 
    TimerTask parserTimerTask = new TimerTask() { 

     @Override 
     public void run() { 
      XmlParser.parsePage(); 
     } 
    }; 

    Timer parserTimer = new Timer(); 
    parserTimer.scheduleAtFixedRate(parserTimerTask, 0, PERIOD); 
} 

我的應用程序運行沒有問題,但是當我關閉使用Tomcat的/etc/init.d/tomcat7停止,然後我檢查日誌(catalina.out)它有這樣一個條目:

SEVERE:Web應用程序[/ MyApplication]似乎啓動了一個名爲[Timer-0]的線程,但未能阻止它。這很可能造成內存泄漏。

我明白這是由我造成的安排計時器,但我的問題是:

  1. 我沒有設置setDeamon爲true,所以不宜定時器防止從Tomcat的關停,而不是左跑?
  2. 我可以在我的應用程序中檢測到Tomcat將要關閉並取消我的計時器嗎?
  3. 我可以用來解決這個問題的其他解決方案是什麼?

謝謝!

UPDATE

我改變了我的代碼爲基礎的一些搜索和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) { 

} 

現在我的新問題:

  1. 我取消TimerTask的第一則計時器,這是正確的?
  2. 我還有其他事情要做嗎?

謝謝!

UPDATE

它不工作。我在contextDestroyed()方法中放了一些日誌語句,在我關閉Tomcat之後,日誌文件只有如下內容:

PowderGodAppWebService - > [Feb Feb 2012 04:09:46 PM] INFO(PowderGodAppWebService.java:45 ):: DETECT TOMCAT服務器將SHUT DOWN PowderGodAppWebService - > [2012年2月7日下午4時09分46秒] INFO(PowderGodAppWebService.java:46):: CANCEL計時器任務和定時器

消除COMPLETE是不在那裏。

我也檢查正在運行的進程(我不是Linux專家,所以我只是使用Mac的活動監視器。

  • 確保沒有java進程正在運行
  • 啓動Tomcat,請注意,java進程的PID
  • 停止Tomcat
  • 找到Tomcat進程走了
  • 啓動Tomcat,注意的PID該Java進程
  • 部署我的war文件
  • 樣品的過程中,看到[定時器0]線程是有
  • 關機的Tomcat
  • 發現該工藝仍然存在
  • 樣品過程
  • 參見[計時器0]仍然存在

FIXED

我改變代碼parserTimer = new Timer(true);所以我的計時器作爲守護程序線程運行,因爲在Tomcat實際關閉後調用contextDestroyed()

「所有的servlet和過濾器將所有的ServletContextListener通知情況下破壞之前已被銷燬。」

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

+0

如果不是那些CANCEL請求在contextDestroyed()? – DaveH 2012-02-07 08:51:50

+0

是的......我想是時候睡覺了,謝謝指出! – 2012-02-07 08:52:54

+0

TimerTask#取消不會中斷任務,如果它正在運行 - 它只會確保它永遠不會再運行 - 但除此之外,我會說你會沒事的那 – DaveH 2012-02-07 08:55:17

回答

57

執行不是在Java EE環境中使用Timer!如果任務拋出運行時異常,則整個Timer被終止並且不再運行。您基本上需要重新啓動整個服務器才能使其再次運行。此外,它對系統時鐘的變化很敏感。

使用ScheduledExecutorService代替。它對任務中拋出的異常以及對系統時鐘的更改都不敏感。您可以通過其shutdownNow()方法關閉它。

這裏是整個ServletContextListener實現如何能看起來像一個例子(注:web.xml需要感謝新@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(); 
    } 

} 
+2

哇!這個答案*非常有用。非常感謝你。對於其他讀者,澄清一點......新的YourParsingJob()應該是接口的一個實例[Runnable](http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable .html)作爲JavaDoc解釋。 – 2014-02-23 09:25:39

+0

如果我需要訪問像EntityManager這樣的資源,會發生什麼情況?您可以訪問這個資源嗎?或者您必須使用'@ Singleton'和'@ Startup' anlotation? – rekiem87 2014-03-11 00:38:02

+2

@ rekiem87:如果您擁有EJB,請使用'@ Schedule'。示例:http://stackoverflow.com/a/8482933和http://stackoverflow.com/q/7499769(下半部分)。目前的問題是關於沒有JPA和EJB的Tomcat。小心尋找答案... – BalusC 2014-03-11 07:01:49

1

的小服務程序破壞方法被調用作爲servlet即將被卸載。你可以從那裏取消定時器,只要你改變了parserTimer本身的範圍,使它成爲一個實例變量。如果你只在init和destroy內部訪問它,我沒有看到問題。

servlet引擎可以自由地卸載servlet,只要它看起來合適,但實際上我只能看到它被稱爲servlet引擎停止 - 其他人可能有其他經驗,雖然這可能會證明我錯了。

-1

嘗試使用框架進行調度。

如果你適應Spring框架,你可以在調度功能使用的版本。

當春天安排我從來沒有任何問題,停止應用服務器。

-1

parseTimer.purge()在您的onContetexyDestroyed.It將刪除隊列中的所有計時器,如果它們存在。