測試併發應用(八)配置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來除錯併發程式碼