您的位置:首页 > 移动开发 > Android开发

得到当前堆栈信息的两种方式(Thread和Throwable)的方法

2016-11-19 16:24 239 查看
今天看到有一个工具类中有一句

Thread.currentThread().getStackTrace()[2].getClassName();

原来工作中遇到的问题:使用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(调用该方法的方法和类)

查看了下jdk的源码。

首先是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;
}


再看下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();


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]。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android java 线程
相关文章推荐