1. 程式人生 > >測試併發應用(八)配置NetBeans來除錯併發程式碼

測試併發應用(八)配置NetBeans來除錯併發程式碼

宣告:本文是《 Java 7 Concurrency Cookbook 》的第八章, 作者: Javier Fernández González 譯者:鄭玉婷

配置NetBeans來除錯併發程式碼

在當今世界,軟體開發的應用必須工作正常,要達到公司的質量標準,還要在將來可以很容易的修改,而且不僅要在有限的時間內,還要儘可能低的費用支出。為了到達這個目標,必需使用 IDE,它集合了一個公共介面和多個工具(編譯器和偵錯程式)為了方便應用程式的開發。

如果你使用 Java 程式語言,那麼 NetBeans 是最普遍的 IDE之一。它有一個內建偵錯程式(integrated debugger)允許你除錯你的應用。在這個指南,你將學習如何改變配置來幫助測試併發應用。

準備

你應該安裝好 NetBeans IDE 。開啟並建立一個新的Java專案。

怎麼做呢…

按照這些步驟來實現下面的例子::

//1.   建立一個類,名為 Task1,並一定實現 Runnable 介面。
public class Task1 implements Runnable {

//2.   宣告2個私有 Lock 屬性,名為 lock1 和 lock2。
private Lock lock1, lock2;

//3.   實現類的建構函式,初始化它的屬性值。
public Task1 (Lock lock1, Lock lock2) {
	this.lock1=lock1;
	this.lock2=lock2;
}

//4.   實現 run() 方法。首先,使用 lock() 方法來獲取 lock1 物件的控制,並寫資訊到操控臺表明已經獲得了。
@Override
public void run() {
lock1.lock();
System.out.printf("Task 1: Lock 1 locked\n");

//5. 然後,使用 lock() 方法來獲取 lock2 物件的控制,並寫資訊到操控臺表明已經獲得了。
lock2.lock();
System.out.printf("Task 1: Lock 2 locked\n");
//最後,釋放這2個lock物件。先是 lock2 物件,然後 lock1 物件。
lock2.unlock();
lock1.unlock();
}

//6.  建立一個類,名為 Task2,並一定實現 Runnable 介面.
public class Task2 implements Runnable{

//7.	宣告2個私有 Lock 屬性,名為 lock1 和 lock2。
private Lock lock1, lock2;

//8.  實現類的建構函式,初始化它的屬性值。
public Task2(Lock lock1, Lock lock2) {
	this.lock1=lock1;
	this.lock2=lock2;
}

//9.   實現 run() 方法。首先,使用 lock() 方法來獲取 lock2 物件的控制,並寫資訊到操控臺表明已經獲得了。
@Override
public void run() {
lock2.lock();
System.out.printf("Task 2: Lock 2 locked\n");

//10. 然後,使用 lock() 方法來獲取 lock1 物件的控制,並寫資訊到操控臺表明已經獲得了。
lock1.lock();
System.out.printf("Task 2: Lock 1 locked\n");

//11. 最後,釋放這2個lock物件。先是 lock1 物件,然後 lock2 物件。
lock1.unlock();
lock2.unlock();
}

//12. 建立例子的主類通過建立一個類,名為 Main 並新增 main()方法。
public class Main {

//13. 宣告2個私有 Lock 屬性,名為 lock1 和 lock2。
Lock lock1, lock2;
lock1=new ReentrantLock();
lock2=new ReentrantLock();

//14. 建立 Task1 物件,名為 task1。
Task1 task1=new Task1(lock1, lock2);

//15. 建立 Task2 物件,名為 task2。
Task2 task2=new Task2(lock1, lock2);

//16. 使用2個執行緒執行這2個 tasks。
Thread thread1=new Thread(task1);
Thread thread2=new Thread(task2);

thread1.start();
thread2.start();

//17.  當2個任務還沒有結束他們的執行,每500毫秒就寫一條資訊給操控臺。使用 isAlive() 方法來檢查執行緒是否結束執行。
while ((thread1.isAlive()) &&(thread2.isAlive())) {
	System.out.println("Main: The example is"+ "running");
	try {
		TimeUnit.MILLISECONDS.sleep(500);
	} catch (InterruptedException ex) {
		ex.printStackTrace();
	}
}

18. 新增一個breakpoint到 Task1 類的run()方法 裡的第一個 println() 方法的呼叫。class.

19.除錯此程式。你可以發現 Debugging 視窗在 NetBeans 的主視窗的左上角。以下的裁圖呈現的視窗外觀裡Task1物件 由於到達了breakpoint,所以進入休眠,而其他的執行緒還在執行:

20. 暫停主執行緒的執行。選擇執行緒,右鍵單擊,然後執行緒Suspend選項。以下的裁圖展示的是新的Debugging視窗外觀。請看下面的裁圖:

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的程式碼如以下的程式碼:

@Override
public void run() {
synchronized(lock1) {
	System.out.printf("Task 1: Lock 1 locked\n");
synchronized(lock2) {
	System.out.printf("Task 1: Lock 2 locked\n");
}
}
}

Task2類的程式碼跟這個類似,只是改變了locks的順序。如果你再此除錯這個例子,你會再次得到deadlock,但是在這次方案,是被deadlock檢測器檢查到的,如你在以下裁圖中看到的:

更多…

有一些控制debugger的選項。在Tools 選單選擇 Options 選項。然後,選擇 Miscellaneous 選項,和 Java Debugger 標籤。以下截圖是視窗的外觀:

在視窗中有2個選項可以控制之前描述的行為:

新 breakpoints 暫停:這個選項,你配置NetBeans的線上程中尋找breakpoint的行為。你可以只暫停有breakpoint的執行緒或者應用的全部執行緒。
步驟恢復:這個選項,你配置NetBeans恢復一個執行緒時的行為。你可以只恢復當前執行緒或者全部執行緒。2個選項都在之前的展示的裁圖中標明瞭。

參見

第八章,測試併發應用:配置Eclipse來除錯併發程式碼