Если вы можете контролировать создание потоков (то есть вызываете new Thread () в своем коде или предоставляете свою собственную ThreadFactory), вы можете создать свой собственный подкласс Thread и использовать его для «инъекции» вызова-стек во время создания потока и вызова start()
в переменные, которые будут в стеке.Например:
public static class KnowledgeableThread extends Thread {
private static class KnowledgeableRunnable implements Runnable {
StackTraceElement[] stackTraceAtInit;
StackTraceElement[] stackTraceAtStart;
private final Runnable actualRunnable;
KnowledgeableRunnable(Runnable actualRunnable){
this.actualRunnable = actualRunnable;
this.stackTraceAtInit = Thread.currentThread().getStackTrace();
}
@Override
public void run() {
actualRunnable.run();
}
}
public KnowledgeableThread(Runnable target, String name) {
super(new KnowledgeableRunnable(target), name);
}
@Override
public synchronized void start() {
try {
Field[] fields = Thread.class.getDeclaredFields();
for(Field f : fields){
if(f.getName().equals("target")){
f.setAccessible(true);
KnowledgeableRunnable knowledgeableRunnable = (KnowledgeableRunnable)f.get(this);
knowledgeableRunnable.stackTraceAtStart = Thread.currentThread().getStackTrace();
}
}
super.start();
} catch (IllegalAccessException e){
throw new IllegalStateException(e);
}
}
}
Если вы остановитесь на точке останова "изнутри" actualRunnable.run()
(например, println
в приведенном ниже коде) и изучите переменные в кадре стека, принадлежащем KnowledgeableRunnable.run()
, у вас должен быть доступ к двум трассам стека.
public static void a(Thread kt){
b(kt);
}
public static void b(Thread kt){
c(kt);
}
public static void c(Thread kt){
kt.start();
}
public static void main(String[] args) throws InterruptedException {
Thread kt = new KnowledgeableThread(new Runnable() {
@Override
public void run() {
System.out.println("Hello Foo-Bar");
}
}, "my-thread");
a(kt);
kt.join();
}