用户操作
[即时聊天] [发私信] [加为好友]
wanghailongID:buaawhl
100861次访问,排名894好友0人,关注者1
buaawhl的文章
原创 49 篇
翻译 0 篇
转载 0 篇
评论 152 篇
最近评论
bruce_lau:看看这个解决方案,对象的缓存和jive差不多,列表也是选id,但是对列表还有缓存,还可以根据字段作散列列表缓存,这样列表的缓存命中率非常高,是一个比较好的数据库缓存解决方案。参见http://shedewang.com/akaladocs/api/com/akala/dbcache/core/BaseManager.html
yipeng6213:个人觉得fastm真的很不错,我之前的模板是用velocity写的,我现在想把它转换成fastm的,但其中velocity模板中的if elseif else 怎么 用fastm替换呢?请问有没有具体的实例 给我参考一下,急!
lidaoguang00109:谢谢您的努力.
这个FastM我使用过了,觉得很不错.
容易上手,特别是可以直接用HTML观察模版的布局形态,有利于界面效果的评估.
现在有一个问题一直困扰我.
就是如果实现一个Table,每一个列被点击后都能排序,用FastM如何实现呢?每一次ValueSet DOM都要重新设置吗?
vkuja2003:楼主做学问的方法很值得学习
noia_zhou:我拜读了你的持久层和cache设计的一些文章,觉得想法很不错。我觉得现在的持久层框架还是挺复杂的,如hibernate等,单看看它10几兆的开发包就知道了,我的初步想法是利用po跟table的字段一致性,通过反射po得到要执行的sql。这样做的好处是少了很多表结构的配置文件。然后做一个简单dao来完成。这里我的想法是做两个dao,一个BaseDao,BaseChaheDao。其中两者都是 继……
文章分类
收藏
    相册
    友情blog
    http://smsbim.bokee.com/
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 线程运行栈信息的获取收藏

    新一篇: HTTP Session | 旧一篇: 分页 & QueryKey & 定长预取

    一、问题的引入

    我们在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。这不就获得对应的ClassMethod信息了吗?这是一个不错的构想,但也只能是一个构想;因为没有这个Statement对象。

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

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

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

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

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

    二、Log4J 1.2的相关实现

    Log4J 1.2JDK1.3时代的作品。我们来看相关源代码。

    [code]

      /**

         Instantiate location information based on a Throwable. We

         expect the Throwable <code>t</code>, to be in the format

           <pre>

            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)

            ...

           </pre>

        */

      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 caller's 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"))

                            // We've found the relevant frame.

    … // 这里的代码省略

                }

                // We haven't 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 <code>t</code>, to be in the format

     

           <pre>

            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)

            ...

           </pre>

     

           <p>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&uuml;lc&uuml;

     *

     */

    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.5Thread Stack Trace

    JDK1.5Thread类里面引入了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.

         *

         * <p>If there is a security manager, and this thread is not

         * the current thread, then the security manager's

         * <tt>checkPermission</tt> method is called with a

         * <tt>RuntimePermission("getStackTrace")</tt> permission

         * to see if it's ok to get the stack trace.

         *

         * <p>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 <tt>StackTraceElement</tt>,

         * 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<Thread, StackTraceElement[]> getAllStackTraces() {

            // check for getStackTrace permission

            // Get a snapshot of the list of all threads

        }

     

    六、总结

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

     

    发表于 @ 2005年01月18日 11:03:00|评论(loading...)|编辑

    新一篇: HTTP Session | 旧一篇: 分页 & QueryKey & 定长预取

    评论

    #于剑秋 发表于2005-02-03 21:30:00  IP:
    TrackBack来自《线程运行栈信息的获取》

    Ping Back来自:blog.csdn.net
    #whiteeagle 发表于2005-03-05 13:47:00  IP:
    TrackBack来自《转载:线程运行栈信息的获取 》

    Ping Back来自:blog.csdn.net
    #smithredsun 发表于2005-02-04 10:22:00  IP: 219.236.16.*
    联系电话:010-82645151
    详情参见:http://www.f c s o f t.com.cn
    什么是eform开发平台?
    eform是基于浏览器的表单自定义工具,eform是页面设计工具,eform内含大量构件.不用写一行代码便能用eform开发出来常见的功能点.

    使用eForm平台有如下好处:
    1、用eform平台开发能降低开发人员的技术门槛,使很低水平的人就能开发一个软件项目中常见的功能.例如数据库的数据增删改查打印等等,而这部分功能往往也占居了一个软件项目的大部分.这样一个软件项目开发成员中可以有一大部分人是中专生甚至是高中生就能胜任.从而大大降低了整个软件项目的开发成本.另一方面因为低水平的开发人员很容易招聘到,这样也使软件项目更加容易完成.

    2、用eform平台开发的代码一致性比较好,以后维护升级方便.因为只有个性化的功能才需要编写事件代码.所以代码量很少,大量的调用底层的代码,这样代码的集成度高.以后维护升级时修改的代码量非常少.


    3、用eform平台开发能大大提高开发效率.eform平台采用对常见的功能和控件内置的方法,使得开发一些常见的功能(如数据库的增删改查,树控件,表格控件)非常容易方便.几乎不用写一行代码.直接通过控件的拖拉然后再设置属性和事件即可完成.开发程序的工作就象是打字员的工作一样.(如图所示开发效率对比示意图)

    4、用eform平台开发能很好地应对软件开发项目成员的流动的问题.因为程序员的离职而造成整个项目瘫痪的事例很多.而用eform平台,因为大家都是采用同一模式开发的表单,因而一个人开发的表单很容易被另一个人看懂和使用.这样就使开发人员的流动造成的影响大大降低.企业不再受制于人.
    5、用eform平台开发可以使项目不再没完没了,无法关闭.因为可以培训最终用户中的精英,让他们掌握eform平台的使用方法,这样大多需求他们便可以自己做好,而不用麻烦软件开发商了.

    eform的设计思路是将数据库程序开发中常用的控制或功能点在eform平台中设计好,通过简单的设置参数或属性即可调用.而遇到很个性化的功能点则可以用传统的代码方式进行开发.因为一个数据库程序开发中大量是增,删,改,查,打印,报表,图表,数据校验等常见的功能点,而这些功能点在eform平台中都做好了,只要简单地设置一下即可完成这些功能点,而且这个设置过程也是可视化的,有相应的设置界面.这样做这些常见的功能点就非常简单快速.而少量的特别的功能点又可通过写代码的方式来完成.也就是说在一张表单中可以一部分功能是直接通过简单的设置一下来完成,另一部分功能是用代码来硬写出来的.这样就达到了常见的功能可以直接调用eform底层的api来实现以提高开发效率,但一个表单又不限定只能实现这些常见功能,你也可随意地用代码来进行无限扩充.这样就达到了既提高了开发效率又能实现很复杂的功能.
    eform开发平台分为eform.j2ee和eform.net两个版本.eform.j2ee是用java编写的,面向j2ee应用.eform.net是用.net编写的,面向.net应用.实际上整个eform开发平台共有三部分的代码,① 一部分是htc js dhtml等前台的代码,② 一部分是java的代码,③ 一部分是.
    #vkuja2003 发表于2007-09-07 10:26:09  IP: 202.45.83.*
    楼主做学问的方法很值得学习
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © buaawhl