项目中遇到500多个线程并发执行,并将线程执行所生成的数据插入MySql数据库,按设想,500个线程,数据库中应有序号连续的500条记录。然而,郁闷的是数据库中的记录在第450条左右就开始不连续,部分记录缺失。500多个线程几乎是独立的,它们之间存在的资源竞争已经做好同步了,因此,由于资源而阻塞的情况排除。再者,500个线程间优先级均等同,我中间做了sleep操作,让线程sleep时间与序号成正比例关系。按理说,每个线程都有机会运行,不存在有部分线程因未被调度到没有运行的情况。
针对上述问题,我先采用打印 Trace Log的方式来调试。关于单步调式,在线程数目很多的情况下,或许不是最好的选择。在 IDE 中通过添加断点的方式调试程序,往往会因为停在某一条线程的某个断点上而错失了其他线程的执行。另外,线程之间的调度往往无法预期,并且会因为断点影响了实际的线程执行顺序。嘿嘿,允许我这么说吧,对于多线程,尤其是很多个线程并发下的单步调式,我还真不很清楚,所以请专家见谅。日志调试的方式,可以帮助我们及时记录每个线程的启动、运行、想要watch的变量信息等等,可以说好处多多。不太好的就是我们往往无法预期哪些关键点需要记录,于是在整个程序的调试过程中,需要不断地加入 Log 调用,我已深有感受。。。这对于大尺寸的软件开发项目无疑是噩梦,而且开发效率会受到很大的影响。因此,上网查询多线程调试工具,以希望解决纠结了我N就的问题。发现目前用的较多的貌似是JDI来开发的debugger吧,于是小试牛刀了下。
一、认识JPDA和JDI
JPD(
Java Platform Debugger Architecture)是一套架构,开发者可以通过这套架构来开发调试用程序。目前这套架构被主流的 Java IDE(如 Eclipse、NetBeans 等)广泛地采用。更多关于JPDA的详细
介绍,可以参见JPDA官方文档以及“深入java调式体系”系列文章。Java Debuger Interface(JDI),定义了代码级别的调试接口。目前,大多数的 JDI 实现都是通过 Java 语言编写的。比如,大家再熟悉不过的 Eclipse IDE,它的调试工具相信大家都使用过。它的两个插件 org.eclipse.jdt.debug.ui 和 org.eclipse.jdt.debug 与其强大的调试功能密切相关,其中 org.eclipse.jdt.debug.ui 是 Eclipse 调试工具界面的实现,而 org.eclipse.jdt.debug 则是 JDI 的一个完整实现。
二、使用JDI开发调式工具
(1)需求
我们要开发的调试工具大致满足一下的通用需求:
1、 独立于目标应用程序。
2、应该足够简单,并且能在通过少量的代码修改就能完成集中配置,这样是帮助开发者不需要付出太多的努力就能开始调试自己的多线程程序。
3、能够抓取足够的信息,比如说异常的信息,程序调用过程中的变量值等等。
4、所生成的 Log 应该足够清晰,能够按不同的线程来分离记录,而不是按照时间的顺序来生成每一条记录,否则会给调试带来不便。
(2)实现
在IBM的技术网站上,提供了一个典型的基于JDI的调试工具的示例,可参考http://www.ibm.com/developerworks/cn/java/j-lo-jdi/#download。该示例依据前面所提到的需求,用来 Profile 一个简单的多线程程序的执行。它展示了线程运行栈快照、方法调用的入口参数值收集、异常过滤定制、类过滤配置、线程 Log 记录等功能。相关的详细信息大家可以参考该网站上的内容。
另外,需要把安装路径下的,如com.sun.java.jdk.win32.x86_1.6.0.013\lib下的tools.jar加入当前工程中,tools.jar中提供了com.sun.jdi的库,开发时调用的接口大多都是这个包下的。
总体来说,JDI的工作过程主要为以下操作:
- 绑定,分析工具和目标调试程序的虚拟机实例绑定;
- 事件注册,分析工具向虚拟机实例注册相关事件请求,整个分析过程采取基于事件驱动的模式。
- 线程运行时信息挖掘。