测试并发应用(八)配置NetBeans来调试并发代码

配置NetBeans来调试并发代码

在当今世界,软件开发的应用必须工作正常,要达到公司的质量标准,还要在将来可以很容易的修改,而且不仅要在有限的时间内,还要尽可能低的费用支出。为了到达这个目标,必需使用 IDE,它集合了一个公共接口和多个工具(编译器和调试器)为了方便应用程序的开发。

如果你使用 Java 编程语言,那么 NetBeans 是最普遍的 IDE之一。它有一个内置调试器(integrated debugger)允许你调试你的应用。在这个指南,你将学习如何改变配置来帮助测试并发应用。

准备

你应该安装好 NetBeans IDE 。打开并创建一个新的Java项目。

怎么做呢…

按照这些步骤来实现下面的例子::


01 //1.   创建一个类,名为 Task1,并一定实现 Runnable 接口。
02 public class Task1 implements Runnable {
03  
04 //2.   声明2个私有 Lock 属性,名为 lock1 和 lock2。
05 private Lock lock1, lock2;
06  
07 //3.   实现类的构造函数,初始化它的属性值。
08 public Task1 (Lock lock1, Lock lock2) {
09     this.lock1=lock1;
10     this.lock2=lock2;
11 }
12  
13 //4.   实现 run() 方法。首先,使用 lock() 方法来获取 lock1 对象的控制,并写信息到操控台表明已经获得了。
14 @Override
15 public void run() {
16 lock1.lock();
17 System.out.printf("Task 1: Lock 1 locked\n");
18  
19 //5. 然后,使用 lock() 方法来获取 lock2 对象的控制,并写信息到操控台表明已经获得了。
20 lock2.lock();
21 System.out.printf("Task 1: Lock 2 locked\n");
22 //最后,释放这2个lock对象。先是 lock2 对象,然后 lock1 对象。
23 lock2.unlock();
24 lock1.unlock();
25 }
26  
27 //6.  创建一个类,名为 Task2,并一定实现 Runnable 接口.
28 public class Task2 implements Runnable{
29  
30 //7.    声明2个私有 Lock 属性,名为 lock1 和 lock2。
31 private Lock lock1, lock2;
32  
33 //8.  实现类的构造函数,初始化它的属性值。
34 public Task2(Lock lock1, Lock lock2) {
35     this.lock1=lock1;
36     this.lock2=lock2;
37 }
38  
39 //9.   实现 run() 方法。首先,使用 lock() 方法来获取 lock2 对象的控制,并写信息到操控台表明已经获得了。
40 @Override
41 public void run() {
42 lock2.lock();
43 System.out.printf("Task 2: Lock 2 locked\n");
44  
45 //10. 然后,使用 lock() 方法来获取 lock1 对象的控制,并写信息到操控台表明已经获得了。
46 lock1.lock();
47 System.out.printf("Task 2: Lock 1 locked\n");
48  
49 //11. 最后,释放这2个lock对象。先是 lock1 对象,然后 lock2 对象。
50 lock1.unlock();
51 lock2.unlock();
52 }
53  
54 //12. 创建例子的主类通过创建一个类,名为 Main 并添加 main()方法。
55 public class Main {
56  
57 //13. 声明2个私有 Lock 属性,名为 lock1 和 lock2。
58 Lock lock1, lock2;
59 lock1=new ReentrantLock();
60 lock2=new ReentrantLock();
61  
62 //14. 创建 Task1 对象,名为 task1。
63 Task1 task1=new Task1(lock1, lock2);
64  
65 //15. 创建 Task2 对象,名为 task2。
66 Task2 task2=new Task2(lock1, lock2);
67  
68 //16. 使用2个线程执行这2个 tasks。
69 Thread thread1=new Thread(task1);
70 Thread thread2=new Thread(task2);
71  
72 thread1.start();
73 thread2.start();
74  
75 //17.  当2个任务还没有结束他们的运行,每500毫秒就写一条信息给操控台。使用 isAlive() 方法来检查线程是否结束运行。
76 while ((thread1.isAlive()) &&(thread2.isAlive())) {
77     System.out.println("Main: The example is"+ "running");
78     try {
79         TimeUnit.MILLISECONDS.sleep(500);
80     } catch (InterruptedException ex) {
81         ex.printStackTrace();
82     }
83 }

18. 添加一个breakpoint到 Task1 类的run()方法 里的第一个 println() 方法的调用。class.

19.调试此程序。你可以发现 Debugging 窗口在 NetBeans 的主窗口的左上角。以下的裁图呈现的窗口外观里Task1对象 由于到达了breakpoint,所以进入休眠,而其他的线程还在运行:

测试并发应用(八)配置NetBeans来调试并发代码

20. 暂停主线程的运行。选择线程,右键单击,然后线程Suspend选项。以下的裁图展示的是新的Debugging窗口外观。请看下面的裁图:

测试并发应用(八)配置NetBeans来调试并发代码

21. 恢复被暂停的2个线程。选择每个线程,右键单击,选择Resume选项。

它是如何工作的…

当使用 NetBeans 试调并发应用, 当试调器到达 breakpoint, 它暂停到达 breakpoint 的线程并在左上角的 Debugging 窗口显示当前正在运行的线程。

你可以使用窗口来暂停或者恢复当前在 Pause 或者 Resume选项中运行的线程。你也可以使用 Variables 标签来查看线程的变量或者属性的值。

NetBeans 也包含了 deadlock 检测器。当你在 Debug 菜单选择 Check for Deadlock 选项,NetBeans 执行对应用的分析来试调决定是否有deadlock 情况。这个例子是很明显的 deadlock。第一个线程首先获得锁lock1,然后锁lock2。第二个线程获得锁与第一个相反的顺序。breakpoint的插入导致了deadlock,但是如果你使用 NetBeans deadlock检测器,你什么也不会发现,所以应该慎重使用此选项。

使用 同步关键词 改变在2个任务中的锁,并再次调试程序。Task1的代码如以下的代码:


1 @Override
2 public void run() {
3 synchronized(lock1) {
4     System.out.printf("Task 1: Lock 1 locked\n");
5 synchronized(lock2) {
6     System.out.printf("Task 1: Lock 2 locked\n");
7 }
8 }
9 }

Task2类的代码跟这个类似,只是改变了locks的顺序。如果你再此调试这个例子,你会再次得到deadlock,但是在这次方案,是被deadlock检测器检查到的,如你在以下裁图中看到的:

测试并发应用(八)配置NetBeans来调试并发代码

更多…

有一些控制debugger的选项。在Tools 菜单选择 Options 选项。然后,选择 Miscellaneous 选项,和 Java Debugger 标签。以下截图是窗口的外观:

测试并发应用(八)配置NetBeans来调试并发代码

在窗口中有2个选项可以控制之前描述的行为:

新 breakpoints 暂停:这个选项,你配置NetBeans的在线程中寻找breakpoint的行为。你可以只暂停有breakpoint的线程或者应用的全部线程。
步骤恢复:这个选项,你配置NetBeans恢复一个线程时的行为。你可以只恢复当前线程或者全部线程。2个选项都在之前的展示的裁图中标明了。

参见

第八章,测试并发应用:配置Eclipse来调试并发代码 

上一篇:阿里云 RDS PostgreSQL 高并发特性 vs 社区版本 (1.6万并发: 3倍吞吐,240倍响应速度)


下一篇:测试并发应用(九)MultithreadedTC测试并发代码