静态代码分析工具是分析应用程序的源代码,同时查找潜在的错误的一组工具。这些工具如Checkstyle、PMD或FindBugs,具有一组预定义的良好实践规则,并解析源代码,查找违反这些规则的地方。使用这些工具的目的是在正式上线执行之前的早期阶段,发现错误或者导致性能底下的位置。编程语言通常提供类似工具,Java也不例外,FindBugs是帮助分析Java代码的一个工具,它是一个开源工具,包含了一系列分析java并发代码的规则。
本节讲学习如何使用此工具分析Java并发应用。
准备工作
在开始之前,从项目网站下载FindBugs(http://findbugs.sourceforge.net/),可以下载独立应用或者Eclipse的插件。本节使用独立版本。
编写本书时,FindBugs(3.0.1)的实际版本不支持Java 9,可以下载支持Java 9 的3.1.0预览版,网址是https://github.com/findbugsproject/findbugs/releases/tag/3.1.0_preview1
实现过程
通过如下步骤实现范例:
-
创建名为Task的类,继承Runnable接口:
public class Task implements Runnable{
-
声明名为lock的私有ReentrantLock属性:
private ReentrantLock lock;
-
实现类构造函数:
public Task(ReentrantLock lock) { this.lock=lock; }
-
实现run()方法,获得锁控制权,设置线程休眠2秒钟,然后释放锁:
@Override public void run() { lock.lock(); try { TimeUnit.SECONDS.sleep(1); lock.unlock(); } catch (InterruptedException e) { e.printStackTrace(); } } }
-
实现本范例主类,创建名为Main的类,包含main()方法:
public class Main { public static void main(String[] args) {
-
声明和创建名为lock的ReentrantLock对象:
ReentrantLock lock=new ReentrantLock();
-
创建10个Task对象和10个执行这些任务的线程,通过调用run()方法启动线程:
for (int i=0; i<10; i++) { Task task=new Task(lock); Thread thread=new Thread(task); thread.run(); } } }
-
导出工程为recipe7.jar文件,使用IDE的菜单选项或者javac、.jar命令来编译和压缩本范例。
-
在Windows系统中运行findbugs.bat命令或者Linux中的findbugs.sh命令,启动FindBugs独立应用。
-
通过点击菜单栏中的File按钮下的New Project**选项,创建新工程:
-
FindBugs软件打开配置工程的窗口,在Project name区域输入Recipe07。在Classpath for analysis field (jar, ear, war, zip, or directory) 里添加工程.jar文件。在Source directories field (optional; classes used when browsing found bugs) 里添加范例的源代码。如下图所示:
-
点击Analyze按钮创建新工程,分析代码。
-
FindBugs软件展示代码分析结果,在本范例中发现了两处问题。
-
单击其中一个问题,将在右侧面板中看到此问题的源代码,并在屏幕底部面板中显示问题描述。
工作原理
下图显示通过FindBugs分析的结果:
在应用中检测出如下两个潜在问题:
- 其中一个问题是在Task类的run()方法中,如果抛出InterruptedExeption异常,任务无法释放锁,因为任务不执行unlock()方法。这在应用中可能导致死锁。
- 另一个问题在Main类的main()方法中,因为直接调用了线程的run()方法,而不是开始线程执行的start()方法。
如果双击其中一个问题,将会看到问题详细信息。由于已经在项目配置中引用源代码,还能看到检测到错误的源代码。如下图所示:
扩展学习
注意FindBugs只能检测一些有问题的情况(是否与并发代码相关)。例如,如果在Task类的run()方法中删除unlock()调用,然后重复此分析。FindBugs不会警告得到任务中的锁,但也永远无法释放它。
使用静态代码分析工具有助于提高代码质量,但不要期望它能够检测所有错误。
更多关注
- 本章“配置NetBeans调试并发代码”小节