1. 程式人生 > >執行緒組中分組執行緒、處理非受控異常

執行緒組中分組執行緒、處理非受控異常

執行緒組中分組執行緒、處理非受控異常


分組執行緒是Java併發API中一個有趣的功能。此功能將一組執行緒作為一個獨立單元,並且能夠對組裡執行緒物件操作提供使用權。例如,如果你想控制一些執行相同任務的執行緒,就可以用一個單獨指令中斷組裡所有的執行緒。

Java提供ThreadGroup了來操作一組執行緒。一個ThreadGroup物件通過執行緒物件生成,另一個ThreadGroup物件,建立執行緒的樹結構。

在“控制執行緒中斷”小節中,我們學會如何使用一個通用方法處理執行緒物件丟擲的所有非捕獲異常。在“處理執行緒非受控異常”小節中,我們編寫一個處理器來解決執行緒丟擲的非捕獲異常。我們也可以使用相同的原理來處理執行緒或執行緒組丟擲的非捕獲異常。

本節中,通過範例學習使用ThreadGroup物件,如何實現和配置處理器來解決一組執行緒丟擲的非捕獲異常。

準備工作

本範例通過Eclipse開發工具實現。如果使用諸如NetBeans的開發工具,開啟並建立一個新的Java專案。

實現過程

通過如下步驟完成範例:

  1. 首先,建立名為MyThreadGroup的類,繼承ThreadGroup類。因為ThreadGroup類本身沒有建構函式,所以在此類中定義具有一個引數的建構函式。重寫ThreadGroup類的uncaughtException()方法用來處理組內的執行緒丟擲的異常:

    public class MyThreadGroup
    extends ThreadGroup { public MyThreadGroup(String name) { super(name); }
  2. 重寫uncaughtException()方法。當ThreadGroup類中的一個執行緒丟擲異常時,呼叫此方法。在這種情況下,此方法記錄異常以及丟擲異常的執行緒資訊,並展現到控制檯上。同時,要注意此方法將中斷ThreadGroup類中其它執行緒執行:

    	@Override
    	public void uncaughtException(Thread t, Throwable e){
    		System.out.printf("The thread %s has thrown an Exception\n"
    , t.getId()); e.printStackTrace(System.out); System.out.printf("Terminating the rest of the Threads\n"); interrupt(); }
  3. 建立名為Task的類,指定其實現Runnable介面:

    public class Task implements Runnable {
    
  4. 實現run()方法。因為我們將用1000與隨機數相除,直到除數為0 的時候丟擲異常,所以引入AritmethicException異常:

        @Override
    	public void run() {
    		int result;
    		Random random = new Random(Thread.currentThread().getId());
    		while(true){
    			result = 1000 / ((int)(random.nextDouble() * 1000000000));
    			if(Thread.currentThread().isInterrupted()){
    				System.out.printf("%d : Interrupted\n", Thread.currentThread().getId());
    				return;
    			}
    		}
    	}
    
  5. 現在實現範例的主類,建立名為Main的類並實現main()方法:

    public class Main {
    	public static void main(String[] args) {
    
  6. 首先,計算將要載入的執行緒數。我們使用Runtime類的availableProcessors() 方法(在此類中名為getRuntie()的靜態方法,通過當前Java程式相關的執行環境物件獲得)。此方法返回Java虛擬機器執行的處理器個數,通常與執行此程式的計算機處理器個數相同:

    		int numberOfThreads = 2 * Runtime.getRuntime().availableProcessors();
    
  7. 建立MyThreadGroup類的物件:

    		MyThreadGroup threadGroup = new MyThreadGroup("MyThreadGroup");
    
  8. 建立Task類的物件:

    		Task task = new Task();
    
  9. 使用Task類建立已計算好個數的執行緒物件,開始執行:

    		for( int i = 0 ; i < numberOfThreads; i ++){
    			Thread t = new Thread(threadGroup, task);
    			t.start();
    		}
    
  10. 然後,在控制檯中輸出ThreadGroup資訊:

    		System.out.printf("Number of Threads: %d\n", threadGroup.activeCount());
    		System.out.printf("Information about the Thread Group\n");
    		threadGroup.list();
    
  11. 最後,在控制檯中輸出來自組內執行緒的狀態資訊:

    				Thread[] threads = new Thread[threadGroup.activeCount()];
    		threadGroup.enumerate(threads);
    		for (int i = 0 ; i < threadGroup.activeCount(); i ++){
    			System.out.printf("Thread %s : %s\n", threads[i].getName(), threads[i].getState());
    		}
    	}
    }
    
  12. 執行程式,檢視結果。

工作原理

在下圖中,可以看到ThreadGroup類中的list()方法以及生成的每個執行緒物件狀態的輸出資訊:

pics/01_08.jpg

因為ThreadGroup類儲存執行緒物件和其他關聯的ThreadGroup物件,所以它能夠獲得這些物件的所有資訊(例如狀態),以及執行所有物件成員的操作(例如中斷)。

檢驗一個執行緒物件是如何丟擲中斷其它物件的異常:

pics/01_09.jpg

當執行緒物件中丟擲一個非捕獲異常時,Java虛擬機器尋找異常中三個可能的處理器。

首先是尋找執行緒的非捕獲異常處理器,在“處理執行緒非受控異常”小節中講解的。如果此處理器不存在,Java虛擬機器尋找ThreadGroup類中的非捕獲異常控制器,即本節中學到的。如果此方法也不存在,Java虛擬機器會尋找預設的非捕獲異常處理器,同樣在“處理執行緒非受控異常”小節中講解的。

如果三種處理器均不存在,Java虛擬器在控制檯輸出異常的堆疊跟蹤,並且終止執行已經丟擲異常的執行緒。

更多關注

  • 本章中“處理執行緒非受控異常”小節。