嗯...不确定这是否可能,但是如果您在单独的线程上运行,如何在 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 ms 的恒定时间操作,那么在主线程上是可以接受的。

最佳答案

编辑:

好的,您想避免堆栈跟踪。我环顾了一下:确定调用者的复杂性实际上在 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();
}

关于Java如何从单独的线程获取调用者?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25736346/

10-10 02:23