<%@ page contentType="text/html; charset=gb2312"%> 线程运行栈信息的获取
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
线程运行栈信息的获取
     发布者: 发布时间:2007-09-23
一、问题的引入
我们在Java程序中使用日志功能(JDK Log或者Log4J)的时候,会发现Log系统会自动帮我们打印出丰富的信息,格式一般如下:

[运行时间] [当前类名] [方法名]

INFO: [用户信息]

具体例子如Tomcat启动信息:

Jul 9, 2004 11:22:41 AM org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on port 8080



看起来这毫无神奇之处,不就是打印了一条信息吗?但如果好奇心重一点,追寻后面的实现原理,会发现这确实很神奇。

上面的Log信息的[当前类名] [方法名]部分 不是用户自己添加的,而是Log系统自动添加的。这意味着Log系统能够自动判断当前执行语句是哪个类的哪个方法。这是如何做到的?

我们翻遍java.lang.reflection package,幻想着找到一个Statement语句级别的Reflection类,通过这个Statement对象获得Method,然后通过这个Method获得declared Class。这不就获得对应的Class和Method信息了吗?这是一个不错的构想,但也只能是一个构想;因为没有这个Statement对象。

再想一下。对了,Java不是有一个Thread类吗?Thread.currentThread()方法获取当前线程,我们能不能通过这个当前线程获取当前运行的Method和Class呢?很遗憾,如果你还在用JDK1.4或以下版本,那么找不到这样的方法。(JDK1.5的情况后面会讲)

再想一下。对了,我们都有很深刻的印象,当系统抛出Exception的时候,总是打印出一串的信息,告诉我们Exception发生的位置,和一层一层的调用关系。我们也可以自己调用Exception的printStackTrace()方法来打印这些信息。这不就是当前线程运行栈的信息吗?找到了,就是它。

Exception的printStackTrace()方法继承自Throwable,那么我们来看一下,JDK的Throwable的printStackTrace()方法是如何实现的。

我们先来看JDK1.3的源代码,会发现Throwable.printStackTrace()方法调用了一个native printStackTrace0()方法。我们找不到任何线索,可以用在我们自己的Java代码中。

那怎么办?Throwable.printStackTrace()的输出结果字符串里面不是包含了当前线程运行栈的所有信息吗?我们可以从这个字符串中抽取自己需要的信息。JDK1.3的时代,也只能这么做了。

二、Log4J 1.2的相关实现
Log4J 1.2是JDK1.3时代的作品。我们来看相关源代码。

[code]

/**

Instantiate location information based on a Throwable. We

expect the Throwable t, to be in the format



java.lang.Throwable

...

at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)

at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)

at org.apache.log4j.Category.callAppenders(Category.java:131)

at org.apache.log4j.Category.log(Category.java:512)

at callers.fully.qualified.className.methodName(FileName.java:74)

...



*/

public LocationInfo(Throwable t, String fqnOfCallingClass) {

String s;



t.printStackTrace(pw);

s = sw.toString();

sw.getBuffer().setLength(0);

…. // 这里的代码省略

}

[/code]



这里我们可以看到整体的实现思路。

首先,t.printStackTrace(pw); 获得stack trace字符串。这个t是 new Throwable()的结果。用户程序调用Log4J方法之后,Log4J自己又进行了4次调用,然后才获得了 t = new Throwable() :

at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)

at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)

at org.apache.log4j.Category.callAppenders(Category.java:131)

at org.apache.log4j.Category.log(Category.java:512)

那么,往下走4行,就可以回到用户程序本身的调用信息:

at callers.fully.qualified.className.methodName(FileName.java:74)

这一行里面,类名、方法名、文件名、行号等信息全有了。解析这一行,就可以获得需要的所有信息。

三、JDK1.4 Log的相关实现
Log4J大获成功,Sun决定在JDK1.4中引入这个Log功能。

为了免去解析StackTrace字符串的麻烦,JDK1.4引入了一个新的类,StackTraceElement。



public final class StackTraceElement implements java.io.Serializable {

// Normally initialized by VM (public constructor added in 1.5)

private String declaringClass;

private String methodName;

private String fileName;

private int lineNumber;



可以看到,恰好包括类名、方法名、文件名、行号等信息。

我们来看JDK1.4 Log的相关实现。

LocationInfo.java 的infoCaller方法(推算调用者)



// Private method to infer the callers class and method names

private void inferCaller() {



// Get the stack trace.

StackTraceElement stack[] = (new Throwable()).getStackTrace();

// First, search back to a method in the Logger class.

…. // 这里的代码省略

// Now search for the first frame before the "Logger" class.

while (ix < stack.length) {

StackTraceElement frame = stack[ix];

String cname = frame.getClassName();

if (!cname.equals("java.util.logging.Logger"))

// Weve found the relevant frame.

… // 这里的代码省略

}

// We haven found a suitable frame, so just punt. This is

// OK as we are only committed to making a "best effort" here.

}



从注释中就可以看出实现思路。过程和Log4J异曲同工。只是免去了解析字符串的麻烦。

四、Log4J 1.3 alpha的相关实现
既然JDK1.4中引入了StackTraceElement类,Log4J也要与时俱进。LocationInfo类也有了相应的变化。



/**

Instantiate location information based on a Throwable. We

expect the Throwable t, to be in the format





java.lang.Throwable

...

at org.apache.log4j.PatternLayout.format(PatternLayout.java:413)

at org.apache.log4j.FileAppender.doAppend(FileAppender.java:183)

at org.apache.log4j.Category.callAppenders(Category.java:131)

at org.apache.log4j.Category.log(Category.java:512)

at callers.fully.qualified.className.methodName(FileName.java:74)

...





However, we can also deal with JIT compilers that "lose" the

location information, especially between the parentheses.



*/

public LocationInfo(Throwable t, String fqnOfInvokingClass) {

if(PlatformInfo.hasStackTraceElement()) {

StackTraceElementExtractor.extract(this, t, fqnOfInvokingClass);

} else {

LegacyExtractor.extract(this, t, fqnOfInvokingClass);

}

}



可以看到,Log4J首先判断Java平台是否支持StackTraceElement,如果是,那么用StackTraceElementExtractor,否则使用原来的LegacyExtractor。

下面来看StackTraceElementExtractor.java



/**

* A faster extractor based on StackTraceElements introduced in JDK 1.4.

*

* The present code uses reflection. Thus, it should compile on all platforms.

*

* @author Martin Schulz

* @author Ceki Gülcü

*

*/

public class StackTraceElementExtractor {

protected static boolean haveStackTraceElement = false;

private static Method getStackTrace = null;

private static Method getClassName = null;

private static Method getFileName = null;

private static Method getMethodName = null;

private static Method getLineNumber = null;

…. // 以下代码省略



可以看到,Log4J 1.3仍然兼容JDK1.3,而且为JDK1.4也做了相应的优化。

五、JDK1.5的Thread Stack Trace
JDK1.5在Thread类里面引入了getStackTrace()和getAllStackTraces()两个方法。这下子,我们不用 (new Throwable()).getStackTrace ();可以调用

Thread.getCurrentThread().getStackTrace()来获得当前线程的运行栈信息。不仅如此,只要权限允许,还可以获得其它线程的运行栈信息。



/**

* Returns an array of stack trace elements representing the stack dump

* of this thread. This method will return a zero-length array if

* this thread has not started or has terminated.

* If the returned array is of non-zero length then the first element of

* the array represents the top of the stack, which is the most recent

* method invocation in the sequence. The last element of the array

* represents the bottom of the stack, which is the least recent method

* invocation in the sequence.

*

*

If there is a security manager, and this thread is not

* the current thread, then the security managers

* checkPermission method is called with a

* RuntimePermission("getStackTrace") permission

* to see if its ok to get the stack trace.

*

*

Some virtual machines may, under some circumstances, omit one

* or more stack frames from the stack trace. In the extreme case,

* a virtual machine that has no stack trace information concerning

* this thread is permitted to return a zero-length array from this

* method.

*

* @return an array of StackTraceElement,

* each represents one stack frame.

*

* @since 1.5

*/

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);

}

}



if (!isAlive()) {

return EMPTY_STACK_TRACE;

}



Thread[] threads = new Thread[1];

threads[0] = this;

StackTraceElement[][] result = dumpThreads(threads);

return result[0];

}



/**

* Returns a map of stack traces for all live threads.

*

* @since 1.5

*/

public static Map getAllStackTraces() {

// check for getStackTrace permission

// Get a snapshot of the list of all threads

}



六、总结
从总的发展趋势来看,JDK不仅提供越来越多、越来越强的功能,而且暴露给用户的控制方法越来越多,越来越强大。


(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
Java中ThreadLocal的设计与使用
Java程序开发中如何应用线程
Sun授权ASEC-Java培训中心
品一杯美味的咖啡:Sun公司认证
SCJP Mock Exam 4
SCJP Mock Exam 3
 
最近评论:
        
春暖花开
wow power leveling2 wow power leveling gvf wow power levelingfcvg wow power leveling wow power leveling wow powerlevelingfcgv wow powerlevelingwq4 wow powerleveling wow powerleveling wow powerleveling world of warcraft power leveling world of warcraft power leveling world of warcraft power leveling world of warcraft power levelingszr world of warcraft power leveling world of warcraft powerleveling world of warcraft powerlevelinge5t world of warcraft powerleveling world of warcraft powerleveling world of warcraft powerleveling wow gold wow gold wow goldrfy5 wow gold wow gold world of warcraft goldre world of warcraft goldgh world of warcraft gold world of warcraft goldfr world of warcraft gold AOC Power Levelinggvgv AGE OF CONAN Power Levelingllwwbb928 t7l6m7cf
        
回复:线程运行栈信息的获取
干洗 干洗机 干洗设备 干洗加盟 干洗加盟 干洗店加盟 干洗店 干洗连锁 干洗店连锁 干洗机价格 水洗机 上海保洁公司 上海保洁 上海清洗公司 上海清洗 上海清洁 上海地毯清洗 视频分享 视频 视频短片 干洗加盟 干洗设备 干洗连锁 干洗机 干洗店 干洗 干洗店加盟 干洗店连锁 干洗机价格 网站优化 google优化 搜索引擎优化 网站推广 seo google优化 google左侧排名 google左侧优化 服装搭配 服饰美容 美容护肤 干洗机 干洗店 干洗 干洗店加盟 干洗设备 干洗加盟 干洗连锁 干洗机价格 加盟干洗店 上海干洗机 干洗店连锁 水洗机 水洗机价格 水洗房设备 石油干洗机 服装 美女写真 美女壁纸 上海保洁公司 上海保洁 上海清洗公司 上海清洗 上海清洁 上海地毯清洗 沙发清洗 干洗 干洗机 干洗设备 短信平台 上海空调维修 上海管道疏通 上海空调加液 上海空调移机 上海空调回收 服饰 组合机床 干洗加盟 干洗设备 干洗机 干洗 上海空调维修 上海中央空调维修 上海空调加液 上海管道疏通 进口管道疏通机 疏通机 上海空调移机 上海空调回收 上海回收中央空调 上海空调保养 上海空调清洗 上海空调安装 上海空调拆装 上海疏通阴沟 上海通水斗 上海管道清洗 上海下水道疏通 保洁公司 上海保洁公司
        
鍥炲
        
那个雨天的想法!
wow gold,wow power leveling.wow power leveling,wow power leveling, max(2739)
        
如果真的有来生!
四川旅游,九寨沟旅游,稻城亚丁旅游,四姑娘山旅游,海螺沟旅游,西藏旅游, max(1241)
        
如果真的有来生!
四川旅游,九寨沟旅游,稻城亚丁旅游,四姑娘山旅游,海螺沟旅游,西藏旅游, max(704)
        
那天的情景!
Maple Story mesos,MapleStory mesos,ms mesos,mesos,SilkRoad Gold, max(740)
        
轻轻走过你的窗前!
world of warcraft gold,cheap world of warcraft gold,warcraft gold,world of warcraft gold,cheap world of warcraft gold,warcraft gold, max(1758)
        
轻轻走过你的窗前!
world of warcraft gold,cheap world of warcraft gold,warcraft gold,world of warcraft gold,cheap world of warcraft gold,warcraft gold max(2987)
        
不在的哪天!
final fantasy xi gil,final fantasy xi gil,final fantasy xi gil,final fantasy xi gil, max(5869)
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号