使用UncaughtExceptionHandler重啟線程

jopen 9年前發布 | 13K 次閱讀 Java開發 UncaughtExceptionHandler

使用UncaughtExceptionHandler重啟線程

我們已經知道,Java中有兩種異常,即已檢測異常和未檢測異常。已檢測的異常必須在拋出語句(throws clause)的方法中指定或者捕獲。未檢測的異常不需要指定或捕獲。因為run()方法不接受拋出語句,所以當一個檢測的異常在一個Thread對象的 run()方法中拋出,我們需要對其進行捕獲并做相應的處理。但是當一個未檢測的異常在一個線程的run()方法中拋出,默認的行為是將堆棧跟蹤信息寫到 控制臺中(或者記錄到錯誤日志文件中)然后退出程序。

幸運的是,Java為我們提供了一個機制,用來捕獲并處理在一個線程對象中拋出的未檢測異常,以避免程序終止。我們可以通過UncaughtExceptionHandler來實現這種機制。

讓我們來做個UncaughtExceptionHandler的使用 示例。在這個例子中,我們已經創建一個線程,這個線程嘗試解析一些本來應該是整數的字符串。我們已經寫出run()方法,讓它在執行時拋出 java.lang.NumberFormatException。當程序不去捕獲異常時,異常經過JVM的同時線程也被殺死。這確實屬于正常的行為,但 不是我們希望看到的。

不使用UncaughtExceptionHandler

在現實生活的應用中,對于一個關鍵的任務,雖然已經失敗了幾次,但是你依然愿意嘗試再執行幾次。下面的例子解釋了這個用例,首先不使用UncaughtExceptionHandler時,線程在執行失敗之后立即終止。

Task.java

class Task implements Runnable
{
   @Override
   public void run()
   {
      System.out.println(Integer.parseInt("123"));
      System.out.println(Integer.parseInt("234"));
      System.out.println(Integer.parseInt("345"));
      System.out.println(Integer.parseInt("XYZ")); //This will cause NumberFormatException
      System.out.println(Integer.parseInt("456"));
   }
}

DemoThreadExample.java

public class DemoThreadExample
{
   public static void main(String[] args)
   {
      Task task = new Task();
      Thread thread = new Thread(task);
      thread.start();
   }
}

下面是線程運行時的輸出:

123
234
345
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "XYZ"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
    at java.lang.Thread.run(Unknown Source)

使用UncaughtExceptionHandler之后

首先,我們實現UncaughtExceptionHandler接口,用來捕獲運行時的任意未檢測的異常。

ExceptionHandler.java

class ExceptionHandler implements UncaughtExceptionHandler
{
   public void uncaughtException(Thread t, Throwable e)
   {
      System.out.printf("An exception has been capturedn");
      System.out.printf("Thread: %sn", t.getId());
      System.out.printf("Exception: %s: %sn", e.getClass().getName(), e.getMessage());
      System.out.printf("Stack Trace: n");
      e.printStackTrace(System.out);
      System.out.printf("Thread status: %sn", t.getState());
      new Thread(new Task()).start();
   }
}

將異常處理程序添加到線程:

class Task implements Runnable
{
   @Override
   public void run()
   {
      Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
      System.out.println(Integer.parseInt("123"));
      System.out.println(Integer.parseInt("234"));
      System.out.println(Integer.parseInt("345"));
      System.out.println(Integer.parseInt("XYZ")); //This will cause NumberFormatException
      System.out.println(Integer.parseInt("456"));
   }
}

再次運行上面的例子,會發現線程能夠持續執行。實際上,如果線程完成了任務,那么它在退出時不會拋出任何異常,從而完成自身生命周期。

123
234
345
An exception has been captured
Thread: 1394
Exception: java.lang.NumberFormatException: For input string: "XYZ"
Stack Trace: 
java.lang.NumberFormatException: For input string: "XYZ"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
    at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
123
234
345
An exception has been captured
Thread: 1395
Exception: java.lang.NumberFormatException: For input string: "XYZ"
Stack Trace: 
java.lang.NumberFormatException: For input string: "XYZ"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at java.lang.Integer.parseInt(Unknown Source)
    at examples.algorithms.sleepingbarber.Task.run(DemoThreadExample.java:24)
    at java.lang.Thread.run(Unknown Source)
Thread status: RUNNABLE
123
234
345

上面的程序實現幫你運行一個線程,在完成任務之前,這個線程會持續運行。通過其他多線程的思想同樣可以實現這種情況。

請注意:UncaughtExceptionHandler可以在無需重啟線程的條件下,將日志記錄變得更加健壯,因為默認日志在線程執行失敗時,不會提供足夠的上下文信息。

學習愉快!

原文鏈接: howtodoinjava 翻譯: ImportNew.com - Angus
譯文鏈接: http://www.importnew.com/14434.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!