嗯...不确定这是否可行,但是如果你在一个单独的线程上运行,那么如何在Java中获取真正的调用者的类名(理想情况下也是方法名)?我想将类名称卸载到一个单独的线程(以便在我每秒执行100多次日志记录操作时不阻止UI线程。)
例如:
class Main {
public void callerMethod() {
Thread.currentThread().getStackTrace()[2].getMethodName(); // This gets me the caller. However, this is expensive to do on the UI Thread 100+ times per second. a call here can take up 70ms
new Thread(new Runnable() {
@Override
public void run() {
new SecondObject().iWantToKnowMyCaller();
}
}).start();
}
}
class SecondObject {
public void iWantToKnowMyCaller() {
// how do i get the caller method here so that it's "callerMethod" from "Main" ?
}
}
用例是这样的:我记录了大量数据,而我根本不想阻止主线程。一些日志记录可能是快速和小数据,但有些可能会记录转储很多东西。问题还在于,现在,编写代码的方式,callerMethod()
大约有600多个入口点,因此重构将是一个相当大的挑战。
可替换地:
如果你能证明Thread.currentThread().getStackTrace()[2].getMethodName();
每次保证是一个小于5毫秒的恒定时间操作,那么在主线程上这是可以接受的。
答案 0 :(得分:4)
编辑:
好的,你想要避免堆栈跟踪。我环顾了一下:确定调用者的复杂性实际上在LogRecord
。如果您可以通过Logger.setSourceClassName()
(根本不是任何字符串)手动设置调用者,则LogRecord将不再构建堆栈跟踪以查找调用者的名称。
public class ThreadTest
{
public static void main( String[] args )
{
LogRecord lr = new LogRecord( Level.INFO, "Hi" );
lr.setSourceClassName( "ThreadTest.main" ); // anything, including null
Logger.getAnonymousLogger().log( lr );
}
}
原始答案:
子类化Thread
会起作用,但我有点怀疑你为什么要这样做。对于调试可能,但这是关于我能想到的唯一用例。 (P.S.我必须在堆栈跟踪中更改您的偏移量。" 2"将获得callerMethod的调用者 - " main"在下面的示例中。)
public class ThreadTest
{
public static void main( String[] args )
{
new Main().callerMethod();
}
}
class Main {
public void callerMethod() {
final String callee = Thread.currentThread().getStackTrace()[1].getMethodName(); // This gets me the caller
new MyThread(new Runnable() {
@Override
public void run() {
new SecondObject().iWantToKnowMyCaller();
}
}){
@Override
public String getInvoker() { return callee; }}.start();
}
}
abstract class MyThread extends Thread implements Invoker {
public MyThread( Runnable r )
{
super( r );
}
}
class SecondObject {
public void iWantToKnowMyCaller() {
// how do i get the caller method here so that it's "callerMethod" from "Main" ?
System.out.println( ((MyThread)(Thread.currentThread())).getInvoker() );
}
}
interface Invoker {
String getInvoker();
}
答案 1 :(得分:0)
public class ThreadTest{
public static void main(String[] args) {
new Main().callerMethod();
}
}
class Main{
public void callerMethod() {
new Thread(new MyRunnable(new Throwable())).start();
}
class MyRunnable implements Runnable {
Throwable t;
MyRunnable(Throwable t) {
this.t = t;
}
@Override
public void run() {
StackTraceElement[] ses = t.getStackTrace();
System.out.println(ses[0].getClassName() + ":" + ses[0].getMethodName() );
}
}
}
答案 2 :(得分:0)
有两种情况。
Thread.
如果您覆盖Thread.start(),
,则可以在那里查看堆栈跟踪。Runnable.
在这种情况下,原则上您无法了解。你可以知道的是,谁通过在构造函数中查看堆栈跟踪来创建Runnable,
,但这不一定是启动线程的相同方法。