2012-02-07 15 views
20

WARファイルがTomcatサーバーにデプロイされているときに、クラスの1つが起動時に呼び出され、init()メソッドがタイマーをスケジュールして、 。シャットダウン時にスケジュールされたタイマーを停止する

私の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とき、私はログを確認します

SEVERE:Webアプリケーション[/ MyApplication]が[Timer-0]という名前のスレッドを開始したように見えますが、停止できませんでした。これはメモリリークを引き起こす可能性が非常に高いです。

私は、これはタイマーをスケジュール私によって引き起こされる理解が、私の質問は:

  1. は私がtrueにsetDeamonを設定しなかったので、タイマーではなく、シャットダウンから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) { 

} 

今私の新しい質問:私は最初にタイマーをTimerTaskををキャンセル

  1. 、これは正しいでしょうか?
  2. 他にもすべきことはありますか?

ありがとう!

UPDATE

それは動作しません。 Tomcatをシャットダウンした後、contextDestroyed()メソッドにいくつかのロギングステートメントを入れます。ログファイルには次のものしかありません:

PowderGodAppWebService - > [07 Feb 2012 04:09:46 PM] INFO(PowderGodAppWebService.java:45) ):: TomcatサーバーがDOWN PowderGodAppWebService SHUTうとしているDETECT - COMPLETEをキャンセル> [2012年2月7日午前4時09分46秒PM] INFO(PowderGodAppWebService.java:46):: CANCEL TIMERタスクとTIMER

ですいない。

実行中のプロセスもチェックしました(私はLinuxのエキスパートではないため、Macのアクティビティモニタを使用しています)。

  • そのJavaプロセスのPID
  • Tomcatを停止
  • はのPIDに注意し、Tomcatプロセスが
  • Tomcatを起動してしまっているが見つかり注意し、何のJavaプロセスが
  • スタートTomcatを実行されていないことを確認してくださいそのJavaプロセス
  • 私の戦争ファイルを展開する
  • [Timer-0]スレッドが存在することを参照してください。
  • シャットダウンTomcatの
  • プロセスは、プロセス
  • 参照[タイマー-0]私はparserTimer = new Timer(true);に私のコードを変更し

FIXED

まだある

  • サンプルがまだあることがわかりました私のタイマーはデーモンスレッドとして実行されるので、contextDestroyed()はTomcatが実際にシャットダウンした後に呼び出されるからです。

    "ServletContextListenersにコンテキスト破棄が通知される前に、すべてのサーブレットとフィルタが破棄されています。

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

  • +0

    それらのキャンセルがが(contextDestroyedにすべきではない):ここでは

    は全体ServletContextListener実装は(:新​​しい@WebListener注釈へweb.xml必要なおかげで無登録のノートが)のように見えることができる方法の例ですか? – DaveH

    +0

    はい...私はそれがベッドのための時間だと思う、指摘のおかげで! –

    +0

    TimerTask#cancelは、現在実行中の場合はタスクを中断しません。再実行されないことを確認しますが、それ以外は、 – DaveH

    答えて

    57

    Do TimerをJava EE環境で使用してください!タスクがランタイム例外をスローした場合、Timer全体が強制終了され、実行されなくなります。基本的には、サーバーを再起動するためにはサーバー全体を再起動する必要があります。また、システムクロックの変化にも敏感です。

    代わりにScheduledExecutorServiceを使用してください。タスクに投げられた例外やシステムクロックの変更には敏感ではありません。 shutdownNow()メソッドでシャットダウンできます。

    @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

    うわー!この回答は*驚くほど*有用でした。どうもありがとうございました。他の読者のために、1つの明確な点...新しいYourParsingJob()は、インタフェース[Runnable]のインスタンスでなければなりません(http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable .html)を参照してください。 –

    +0

    そして、もし私が 'EntityManager'のようなリソースにアクセスする必要があれば、これにアクセスできますか、' @ Startup'アノテーションで '@ Singleton'を使わなければなりませんか? – rekiem87

    +2

    @ rekiem87:EJBを手元に持っている場合は、代わりに '@ Schedule'を使います。例:http://stackoverflow.com/a/8482933およびhttp://stackoverflow.com/q/7499769(下の部分)。現在の質問は、JPAとEJBを持たないTomcatについてです。回答を探す際に注意してください。 – BalusC

    1

    サーブレットは、サーブレットがアンロードされようとしているようにメソッドが呼び出され破壊します。 parserTimer自体のスコープを変更してインスタンス変数にすることを条件として、そこからタイマーをキャンセルすることができます。あなたがinit内からのみアクセスして破壊するならば、私はそれに問題は見られません。

    サーブレットエンジンは、サーブレットが適切であると見なされると自由にアンロードできますが、私はサーブレットエンジンが停止したときに呼び出されるのを見ただけです - これは間違っているかもしれない。

    -1

    スケジューリングのフレームワークを使用してください。

    Spring Frameworkに適応する場合は、スケジューリング機能のビルドを使用できます。

    Springでスケジューリングするときに、アプリケーションサーバーを停止するのに問題はありませんでした。

    -1

    parseTimer.purge()をあなたのonContetexyDestroyedに入れます。存在する場合、キュー内のすべてのタイマーを削除します。

    関連する問題