簡體   English   中英

Java如何從單獨的線程獲取調用者?

[英]Java how to get caller from separate thread?

嗯......不確定這是否可行,但如果你在一個單獨的線程上運行,怎么會在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" ?
    }
}

用例是這樣的:我正在記錄大量數據,我根本不想阻止主線程。 一些日志記錄可能是快速和小數據,但有些可能會記錄轉儲很多東西。 問題還在於,現在,編寫代碼的方式,大約有600多個入口點進入callerMethod() ,因此重構將是一個相當大的挑戰。

或者:

如果你能證明Thread.currentThread().getStackTrace()[2].getMethodName(); 保證是每次少於5毫秒的恆定時間操作,那么在主線程上可以接受。

編輯:

好的,您想要避免堆棧跟蹤。 我環顧了一下:確定調用者的復雜性實際上是在LogRecord 如果您可以通過Logger.setSourceClassName()手動設置調用者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將起作用,但我有點質疑你為什么要這樣做。 對於調試可能,但這是我能想到的唯一用例。 (PS我必須改變堆棧跟蹤中的偏移量。“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();
}
    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() );
        }
    }
}

有兩種情況。

  1. 你擴展了Thread. 如果重寫Thread.start(),可以在那里查看堆棧跟蹤。
  2. 您實現了Runnable. 在這種情況下,原則上你無法知道。 您可以知道的是Runnable,通過在構造函數中查看堆棧跟蹤來創建Runnable,但這不一定與啟動該線程的方法相同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM