2011-06-15 10 views
4

これは珍しいことです:最初に現在実行中のスレッドを生成したクラス/メソッドを取得できますか?スタックトレースの実行は、当然のことながら、現在のスレッドの呼び出しスタックの最上部で停止します。現在のスレッドが生成されたクラスとメソッドの名前を取得できますか?

+1

私はあなたが何か重要なものではなく、いくつかのハッキングデバッグのためにこれをやってくれることを願っています。 –

+0

ハハ、あなたは正しく仮定します。 --D – Wilco

+0

関連していますが(同じではありません):[Javaでスタックトレースを作成する](http://stackoverflow.com/questions/6270256/forging-a-)-私はこのパスを開始してから私の鼻を止めていません。 stack-trace-in-java) –

答えて

7

はい、できます: 私は2つの方法を提供します:1つの標準と1つのセミハック。

ほとんどの回答は、Javaの組み込み関数であると考えられていますが、外に出ています。

セキュリティマネージャをインストールしてSecurityManager.getThreadGroup()を上書きすると、スタックトレースを簡単に取得できます。オプションで、残りのメソッドもオーバーライドすることで、セキュリティチェックの残りの部分を無効にすることもできます。

ハッキーワン:メインスレッド(mainという名前のメソッドとmain(String [] args)メソッド)でInheritableThreadLocalをインストールします。保護されているを上書きすると、完了です。

注:作成中のスレッドと親スレッド(参照)のスタックトレースは取得できますが、問題をトレースするのに十分なはずです。

私はそれがどれほど簡単かを示すために簡単なサンプルを書くことにしました: ここで結果を見ることができます。サンプルを見ると、私はこのサイトに投稿した最もエレガントなソリューションだと思います。ほとんどがb/cですが、それは明らかではありませんがシンプルでスマートです。

package bestsss.util; 

import java.util.Arrays; 

public class StackInterceptor extends InheritableThreadLocal<StackTraceElement[]>{ 
    public static final StackInterceptor instance; 
    static{ 
     instance = new StackInterceptor(); 
     instance.set(new Throwable().getStackTrace()); 
    } 

    @Override 
    protected StackTraceElement[] childValue(StackTraceElement[] parentValue) { 
     return new Throwable().getStackTrace(); 
    } 

    //test// 
    public static void main(String[] args) { 
     Runnable r= new Runnable(){ 
      @Override 
      public void run() { 
       System.out.printf("%s - creation stack: %s%n", Thread.currentThread(), Arrays.toString(instance.get()).replace(',', '\n')); 
      }   
     }; 

     Thread t1 = new Thread(r, "t1"); 
     //spacer 
     Thread t2 = new Thread(r, "t2"); 
     t1.start(); 
     t2.start();  
    } 
} 
 
Thread[t1,5,main] - creation stack: [bestsss.util.StackInterceptor.childValue(StackInterceptor.java:13) 
bestsss.util.StackInterceptor.childValue(StackInterceptor.java:1) 
java.lang.ThreadLocal$ThreadLocalMap.(ThreadLocal.java:334) 
java.lang.ThreadLocal$ThreadLocalMap.(ThreadLocal.java:242) 
java.lang.ThreadLocal.createInheritedMap(ThreadLocal.java:217) 
java.lang.Thread.init(Thread.java:362) 
java.lang.Thread.(Thread.java:488) 
bestsss.util.StackInterceptor.main(StackInterceptor.java:25)] 
Thread[t2,5,main] - creation stack: [bestsss.util.StackInterceptor.childValue(StackInterceptor.java:13) 
bestsss.util.StackInterceptor.childValue(StackInterceptor.java:1) 
java.lang.ThreadLocal$ThreadLocalMap.(ThreadLocal.java:334) 
java.lang.ThreadLocal$ThreadLocalMap.(ThreadLocal.java:242) 
java.lang.ThreadLocal.createInheritedMap(ThreadLocal.java:217) 
java.lang.Thread.init(Thread.java:362) 
java.lang.Thread.(Thread.java:488) 
bestsss.util.StackInterceptor.main(StackInterceptor.java:27)] 

幸運と幸せなハッキング。

+0

InheritableThreadLocalのソリューションは美しいものです。 main()のソースが利用できない場合(例えば、アプリケーションサーバの場合) –

+0

main()は最初の(通常はermほぼ)メソッドですアプリケーションで呼び出すことができます。使用できない場合は、threadLocalを初期化した後、生成されたすべての子(およびグランド・チャイルド++)スレッドがトレース可能になります。要するに、できるだけ早くinit部分を行います。 – bestsss

1

通常、

スレッドの作成を制御できる場合は、スレッドをサブクラス化して、スタックトレースをコンストラクタに登録できます。もちろん、これはスレッドを作成したメソッドであり、必ずしも.start()と呼ばれるものではありません。したがって、このメソッドをよりよくオーバーライドします。

しかし、多くの場合、どのメソッドがスレッドを開始したのではなく、実行者の​​にタスクをサブミットしたかを知りたいスレッドプールを使用します。

+0

プールを制御する場合、threadFactoryを制御することは不思議ではないので、スレッドファクトリです。 – bestsss

+0

@bestsss:はい。私の指摘は、このスレッドファクトリメソッドは通常、**あなたが本当に知りたい**ではないことです。誰が(どのメソッドを)スレッドプールに(または誰がその実行可能オブジェクトを作成して)送信したのかを知りたいでしょう。このために、スレッドプールはすべてのタスクにメタデータを追加する必要があり、何らかの方法でこれを取得する手段を提供します。 –

+1

ŭlo、タスクを装飾するために 'AbstractExecutorService'に' newTaskFor(...) 'があります。逆に、第1のタスクがいつスレッドを生成したかを知ることは非常に重要である。理由は分かりませんが、新しく作成されたスレッドは親からかなり継承され、リークを防ぐために(ClassLoader、AccessControlContext、ThreadGroupなど)、徹底したThreadFactoryを使用します。 – bestsss

0

スポーンオブジェクトの協力を得て、スレッドオブジェクトに情報を書き込むことができます(たとえば、ハックな方法が必要な場合はスレッドの名前、この目的のためのフィールドを作成できます)。後でデバッグなどに使用することができます。 しかし、私はこの情報を得るための "組み込みの"方法はないと思います。

+1

*しかし、私は、この情報を取得するための「組み込み」の方法はないと考えています。SecurityManagerは、そのまさにその理由のために作成され、潜在的なセキュリティリスクコードへの呼び出しをトレースします。 – bestsss

+0

本当にありがとうございます。 – DNA

0

いいえ、不可能です。おそらく、これを達成する方法は、AspectJを使用してbeforeアドバイスをThread.start()にすることです...もちろん、Thread、パッチJDKコード(別のブートCLASSPATH)などをサブクラス化できますが、AspectJは最もポータブルでエレガントなソリューションです。

+0

doh、それほど多くの作業:) – bestsss

関連する問題