7

Tomcat で、webapp がデーモン スレッドを停止した場合、tomcat は shutdown.sh でシャットダウンできません。

例えば:

public class demo implements ServletContextListener{

  public void contextDestroyed(ServletContextEvent arg0) {
    // TODO Auto-generated method stub
    // yes,we can cancel timer in here,but this is not the major problem
   }

  public void contextInitialized(ServletContextEvent arg0) {        
    Timer timer = new Timer();
    timer.schedule(new Test(), 1000, 1000*10);
    }
}

public class Test extends TimerTask{  
@Override
public void run() {
    System.out.println("AAAA");        
   }
}

上記同様、tomcatはshutdown.shでシャットダウンできません。jvisualvm から、スレッド インスペクターは次のように述べています。

"Timer-0" - Thread t@40
   java.lang.Thread.State: TIMED_WAITING
    at java.lang.Object.wait(Native Method)
    - waiting on <3957edeb> (a java.util.TaskQueue)
    at java.util.TimerThread.mainLoop(Timer.java:552)
    at java.util.TimerThread.run(Timer.java:505)

   Locked ownable synchronizers:
    - None

スタック情報は、どの Java クラスがスレッドを作成したかを指摘していませんでした。私の質問は、多くの webapps からスレッドを作成した人を見つける方法です。

ありがとう!

4

4 に答える 4

22

これは、最も速い/最も信頼できるものから最も遅い/最も難しいものへとソートされたアプローチのリストです。

  1. クラスのソースがある場合は、コンストラクターで例外を作成します (実際にはスローしません)。スレッドがいつ作成されたかを知る必要がある場合は、単に調べたり印刷したりできます。

  2. ソースがない場合は、スレッド名が作成者のヒントになります。

  3. 名前が一般的なサービス ( など) を示唆している場合はjava.util.Timer、IDE のコンストラクターで条件付きブレークポイントを作成できます。条件はスレッド名にする必要があります。誰かがこの名前でスレッドを作成すると、デバッガーは停止します。

  4. スレッドが多すぎない場合は、 のコンストラクターにブレークポイントを設定しますThread

  5. スレッドが多い場合は、アプリにデバッガーをアタッチしてフリーズします。次に、スタック トレースを調べます。

  6. 他のすべてが失敗した場合は、Java ランタイムのソース コードを取得し、監視するクラスにログ記録コードを追加し、新しいものをコンパイルしrt.jarて、元のものを自分のバージョンに置き換えます。これを本番環境で試さないでください。

  7. お金が問題にならない場合は、Compuware APMなどの動的トレース ツールを使用できます。Linux または Solaris を使用している場合は、それぞれSystemTapと dtrace を試すことができます。

于 2013-09-25T08:29:21.037 に答える
2

rt.jar クラスを変更しようとする代わりに、小さな Java Instrumentation エージェントを作成して、スレッド コンストラクター (およびそこにスタック ダンプ) をラップすることもできます。

于 2016-01-31T21:23:51.247 に答える
2

クラスを制御できる場合は、作成時にスタック トレースをキャッチできます。

public class Test extends TimerTask {
  final StackTraceElement[] callerStack;

  public Test () {
    callerStack = Thread.currentThread().getStackTrace();
  }

  @Override
  public void run() {
    System.out.println("AAAA");
    System.out.println("Creator: "+Arrays.asList(callerStack));
  }

  @Override
  public String toString () {
    return "Test created by "+Arrays.asList(callerStack);
  }
}
于 2013-09-25T08:10:55.007 に答える