得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
来源:互联网 发布:js中indexof的用法 编辑:程序博客网 时间:2024/05/16 18:32
今天进行slf4j中logger的同步封装,主要目的是为了以后方便更换日志实现系统。
遇到的问题:使用Thread.currentThread().getStackTrace()[1].getClassName()得到的是当前类而不是调用类,见下面代码:
private org.slf4j.Logger logger = null;/** * construction method */public Logger(){// get the current class loggerlogger = LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());}
所以打印日志的时候并没有得到日志真正所属类的信息。
然后,我进行了一组测试:
测试A:
public class ThreadTest {public static void TestString(){StackTraceElement[] arr = new Exception().getStackTrace();for(int i=0;i<=arr.length-1;i++){System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());}}}
public class App { public static void main( String[] args ) { ThreadTest.TestString(); }}
结果是:
test.ThreadTest;TestString;ThreadTest.java(当前方法和类)
test.App;main;App.java(调用该方法的方法和类)
测试B:
public class ThreadTest {public static void TestString(){StackTraceElement[] arr = Thread.currentThread().getStackTrace();for(int i=0;i<=arr.length-1;i++){System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());}}}
App类同上,得到的结果是:
java.lang.Thread;getStackTrace;Thread.java(Thread的信息)
test.ThreadTest;TestString;ThreadTest.java(当前方法和类)
test.App;main;App.java(调用该方法的方法和类)
啥米情况???难道就是因为Thread的getStackTrace比Throwable(Exception的父类)的getStackTrace多打了一段Thread类的信息???
由于不确定是不是真的是这样子的,故去查看了下jdk的源码(纯属装X,不抱幻想)。
首先是Throwable的getStackTrace方法,代码如下:
public StackTraceElement[] getStackTrace() { return getOurStackTrace().clone(); } private synchronized StackTraceElement[] getOurStackTrace() { // Initialize stack trace field with information from // backtrace if this is the first call to this method if (stackTrace == UNASSIGNED_STACK || (stackTrace == null && backtrace != null) /* Out of protocol state */) { int depth = getStackTraceDepth(); stackTrace = new StackTraceElement[depth]; for (int i=0; i < depth; i++) stackTrace[i] = getStackTraceElement(i); } else if (stackTrace == null) { return UNASSIGNED_STACK; } return stackTrace; }
貌似没有什么不对劲的地方哈,其中
int depth = getStackTraceDepth();
stackTrace[i] = getStackTraceElement(i);两个方法都是native的,不予深究了。这里没有找到问题,就去看了下Thread的getStackTrace方法,代码如下:
public StackTraceElement[] getStackTrace() { if (this != Thread.currentThread()) { // check for getStackTrace permission SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission( SecurityConstants.GET_STACK_TRACE_PERMISSION); } // optimization so we do not call into the vm for threads that // have not yet started or have terminated if (!isAlive()) { return EMPTY_STACK_TRACE; } StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this}); StackTraceElement[] stackTrace = stackTraceArray[0]; // a thread that was alive during the previous isAlive call may have // since terminated, therefore not having a stacktrace. if (stackTrace == null) { stackTrace = EMPTY_STACK_TRACE; } return stackTrace; } else { // Don't need JVM help for current thread return (new Exception()).getStackTrace(); } }
乍一看也没啥错啊~~~不对,突然间跟着逻辑走一下,在if语句里面因为
this != Thread.currentThread()是为true的,所以方法会执行else里面的语句,里面是啥!!!!
return (new Exception()).getStackTrace();All right!就是这里,这里jvm去执行了new Exception().getStackTrace();就是这句话让使用Thread的getStackTrace方法就有可能多打印一句java.lang.Thread;getStackTrace;Thread.java出来!这也就是为什么使用
logger = LoggerFactory.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());会得不到正确的日志信息的原因了!
应该就是这样子了,为了验证我想的对不对,写了一个测试验证的例子,代码如下:
public class TestException {public static StackTraceElement[] getStackTrace() {return new Exception().getStackTrace();}}
public class ThreadTest {public static void TestString(){StackTraceElement[] arr = TestException.getStackTrace();for(int i=0;i<=arr.length-1;i++){System.out.println(arr[i].getClassName()+";"+arr[i].getMethodName()+";"+arr[i].getFileName());}}}
public class App { public static void main( String[] args ) { ThreadTest.TestString(); }}
执行之后的结果是:
test.TestException;getStackTrace;TestException.java
test.ThreadTest;TestString;ThreadTest.java
test.App;main;App.java
红色的一行即证明了我的想法是正确的!
所有的验证至此结束了,这个问题最后解决办法很简单,要么使用new Exception().getStackTrace()[1];要么使用Thread.currentThread().getStackTrace()[2]。
虽然这个问题很小,也很基础,但是我还是很兴奋,毕竟粘上了源码,顿时逼格升高不少~~~
新手上路,高手饶命~!
- 得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
- Runnable和Thread两种方式创建线程的比较
- 堆栈的两种实现方式
- 堆栈的两种实现方式
- JAVA 利用Throwable和Thread分析堆栈跟踪元素
- thread两种启动方式的区别
- Thread 两种实现方式的区别
- Java线程总结(一):创建线程的两种方式Thread和Runnable
- java--(多线程创建的两种方式Thread类和Runnable接口)
- 查看java当前线程的堆栈信息
- 从网络上获取图片的两种方式讲解:thread+handle和AsyncTask方式
- VC得到当前电脑的CPU信息
- 得到用户当前运行的进程信息
- 堆栈处理二叉树先序输出的两种方式
- Runnable和Thread 两种实现方式的区别和联系:
- 得到当前方法的名字Thread.currentThread().getStackTrace()[1].getMethodName();
- 得到当前方法的名字Thread.currentThread().getStackTrace()[1].getMethodName();
- 两种获得WMI信息的方式
- hdu1698 Just a Hook(线段树)
- C语言字符输出格式化
- Visualizing and Understanding convolutional networks
- php内置服务器配置
- OGEngine介绍
- 得到当前堆栈信息的两种方式(Thread和Throwable)的纠结
- jquery选显卡的实现
- 附近的鬼地方
- 内部类
- 函数 (上)
- IRQL中断请求级别及APC_LEVEL讨论
- Spring MVC "The request sent by the client was syntactically incorrect ()"解决办法
- SqlServer一键复制数据库脚本
- Regex.Match(string str)导致str堆栈内存被一直占用