我可以获取当前线程生成的类和方法的名称吗?

时间:2011-06-15 21:50:57

标签: java multithreading

这是一个不寻常的问题:是否有可能获得最初产生当前正在运行的线程的类/方法?运行堆栈跟踪将自然停在当前线程的调用堆栈顶部。

4 个答案:

答案 0 :(得分:7)

是的,您可以: 我为您提供两种方式:一种是标准方式,一种是半方式。

大多数答案都过分了,而它应该是Java中的内置函数。

安装安全管理器并覆盖SecurityManager.getThreadGroup(),您可以轻松获得堆栈跟踪,也可以通过覆盖其余方法来禁用其余的安全检查。

Hacky one:在主线程中安装一个InheritableThreadLocal(名为main的那个并由方法main(String [] args)运行)。覆盖受保护的InheritableThreadLocal.childValue(T parentValue),您就完成了。

注意:您将获得正在创建的线程的堆栈跟踪和父线程(引用),但这应该足以跟踪问题。

我决定编写超级简单的样本来说明它是多么容易: 在这里你可以看到结果。看一下这个样本,我想这是我在这个网站上发布过的最优雅的解决方案,主要是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)]

祝你好运和快乐的黑客攻击。

答案 1 :(得分:1)

通常,没有。

如果您可以控制线程创建,则可以继承Thread并在构造函数中注册堆栈跟踪。当然,这是创建线程的方法,不一定是调用.start()的线程。因此,更好地覆盖这种方法。

但是通常你会使用线程池,在那里你想知道哪个方法将任务提交给执行者的execute(),而不是哪个方法启动了线程。

答案 2 :(得分:0)

可以通过产生对象的合作 - 它可以将信息写入Thread对象(例如,如果你想要一个hacky方式,可以写入线程的名称,或者你可以为此目的创建一个字段),你可以后来用于调试等。但我不认为有任何'内置'方式来获取此信息。

答案 3 :(得分:0)

不,这是不可能的。实现这一点的方法可能是使用AspectJ在before上提供Thread.start()建议...当然,您可以继承Thread,修补JDK代码(不同的引导CLASSPATH)等,但AspectJ似乎是最便携和优雅的解决方案。