<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    szhswl
    宋針還的個人空間
    跟蹤無法預期的運行時異常可能是一件又慢又費力的事情,只獲得默認線程名稱和堆棧跟蹤通常是不夠的。在文中,Java 開發(fā)人員 John Zukowski 向您展示了如何通過替代默認行為來定制輸出。 他還對比了通過細分 ThreadGroup 定制輸出的老方法與通過提供自己的 UncaughtExceptionHandler 定制輸出的新方法。

      雖然我們不想創(chuàng)建在無法預期時拋出運行時異常的程序,但這種情況還是會發(fā)生——尤其是第一次運行復雜程序時。通常是使用默認行為、打印堆棧溢出和結(jié)束線程的生命來處理這些異常。

      從哪里發(fā)現(xiàn)默認行為?每個線程都屬于一個由 java.lang.ThreadGroup 類表示的線程組。顧名思義,線程組允許您將線程組合在一起。您可能是為了方便而將線程組合,例如,一個線程池中的所有線程都屬于組 X,而另一個池的所有線程則屬于組 Y,或者是為了訪問控制而將線程進行組合。組 X 中的線程無權(quán)訪問或改變組 Y 中的線程,除非它們都在同一線程組內(nèi)(或在一個子組內(nèi))。

      在 Tiger 之前, ThreadGroup 類提供了一種處理未捕獲異常的方法: ThreadGroup 的 uncaughtException() 方法。如果異常不是 ThreadDeath ,則將線程的名稱和堆棧回溯(stack backtrace)發(fā)送到 System.err 。但是 Tiger 添加了另一種方法: Thread.UncaughtExceptionHandler 接口。細分 ThreadGroup 或安裝該新接口的實現(xiàn)都允許您更改默認行為。我們將對 Tiger 之前和之后提供的方法都進行研究。

      使用 ThreadGroup 的定制行為

      發(fā)生未捕獲的異常時,默認行為是將堆棧溢出打印輸出到系統(tǒng)錯誤( System.err )中,如清單 1 中所示。不需要使用任何命令參數(shù)來啟動程序。

      清單 1. 線程溢出示例

    public class SimpleDump {
     public static void main(String args[]) {
      System.out.println(args[0]);
     }
    }

      不使用任何參數(shù)運行該程序?qū)⑸汕鍐?2 中的輸出。盡管它不是一個很長的堆棧跟蹤,但它是一個完整的堆棧跟蹤。

      清單 2. 默認線程溢出輸出

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
    at SimpleDump.main(SimpleDump.java:3)

      正如 Java 平臺的許多東西一樣,如果不喜歡默認行為,您可以對其進行更改。在 Java 平臺的 Tiger 版以前的版本中,不能替代所有線程的默認行為,但是可以創(chuàng)建一個新的 ThreadGroup ,并更改在該組內(nèi)創(chuàng)建的任何線程的默認行為。您可以重寫 uncaughtException(Thread t, Throwable e) 方法來定制該行為。然后,當發(fā)生未預料的運行時異常時,該線程組內(nèi)創(chuàng)建的任何線程都將獲得新的行為。不過,最好是修復基礎問題,我將提供一個簡單的示例,說明更改默認行為所必需的步驟。清單 3 展示了將執(zhí)行代碼放入新線程的調(diào)整過的測試程序:

      清單 3. 調(diào)整過的線程溢出示例

    public class WindowDump {
     public static void main(String args[]) throws Exception {
      ThreadGroup group = new LoggingThreadGroup("Logger");
      new Thread(group, "myThread") {
       public void run() {
        System.out.println(1 / 0);
       }
      }.start();
     }
    }

      LoggingThreadGroup 類是一個新的內(nèi)容,清單 4 中顯示了它的定義。為了進行說明,通過重寫 uncaughtException() 方法實現(xiàn)的特殊行為將在一個彈出窗口中顯示該異常,這項操作是在特殊 Handler 的幫助下使用 Java Logging API 來完成的。

      清單 4. LoggingThreadGroup 的定義

    import java.util.logging.*;

    public class LoggingThreadGroup extends ThreadGroup {
     private static Logger logger;
     public LoggingThreadGroup(String name) {
      super(name);
     }
     public void uncaughtException(Thread t, Throwable e) {
      // Initialize logger once
      if (logger == null) {
       logger = Logger.getLogger("example");
       Handler handler = LoggingWindowHandler.getInstance();
       logger.addHandler(handler);
      }
      logger.log(Level.WARNING, t.getName(), e);
     }
    }

      這里創(chuàng)建的定制 Handler 的類型為 LoggingWindowHandler ,該類型的定義在清單 5 中。處理程序使用了一個支持類 LoggingWindow ,該類將異常顯示在屏幕上。 清單 6 中顯示了該類的定義。 Handler 的 public void publish(LogRecord record) 方法實現(xiàn)了一些重要操作。其余操作大部分只與配置有關(guān)。

      清單 5. LoggingWindowHandler 的定義

    import java.util.logging.*;

    public class LoggingWindowHandler extends Handler {
     private static LoggingWindow window;
     private static LoggingWindowHandler handler;

     private LoggingWindowHandler() {
      configure();
      window = new LoggingWindow("Logging window...", 400, 200);
     }

     public static synchronized LoggingWindowHandler getInstance() {
      if (handler == null) {
       handler = new LoggingWindowHandler();
      }
      return handler;
     }

     /**
     * Get any configuration properties set
     */
     private void configure() {
      LogManager manager = LogManager.getLogManager();
      String className = getClass().getName();
      String level = manager.getProperty(className + ".level");
      setLevel((level == null) ? Level.INFO : Level.parse(level));
      String filter = manager.getProperty(className + ".filter");
      setFilter(makeFilter(filter));
      String formatter = manager.getProperty(className + ".formatter");
      setFormatter(makeFormatter(formatter));
     }

     private Filter makeFilter(String name) {
      Filter f = null;
      try {
       Class c = Class.forName(name);
       f = (Filter)c.newInstance();
      } catch (Exception e) {
       if (name != null) {
        System.err.println("Unable to load filter: " + name);
       }
      }
      return f;
     }

     private Formatter makeFormatter(String name) {
      Formatter f = null;
       try {
        Class c = Class.forName(name);
        f = (Formatter)c.newInstance();
       } catch (Exception e) {
        f = new SimpleFormatter();
       }
       return f;
      }

      // Overridden abstract Handler methods

      public void close() {
      }

      public void flush() {
     }

     /**
     * If record is loggable, format it and add it to window
     */
     public void publish(LogRecord record) {
      String message = null;
      if (isLoggable(record)) {
       try {
        message = getFormatter().format(record);
       } catch (Exception e) {
       reportError(null, e, ErrorManager.FORMAT_FAILURE);
       return;
      }
     try {
      window.addLogInfo(message);
     } catch (Exception e) {
      reportError(null, e, ErrorManager.WRITE_FAILURE);
     }
    }
    }
    }                            

      清單 6. LoggingWindow 的定義

    import java.awt.*;
    import javax.swing.*;

    public class LoggingWindow extends JFrame {
     private JTextArea textArea;
     
     public LoggingWindow(String title, final int width,
     final int height) {
      super(title);
      EventQueue.invokeLater(new Runnable() {
       public void run() {
        setSize(width, height);
        textArea = new JTextArea();
        JScrollPane pane = new JScrollPane(textArea);
        textArea.setEditable(false);
        getContentPane().add(pane);
        setVisible(true);
       }
      });
     }  

     public void addLogInfo(final String data) {
      EventQueue.invokeLater(new Runnable() {
       public void run() {
        textArea.append(data);
       }
      });
     }
    }

      執(zhí)行 清單 3 中的 WindowDump 程序?qū)⒊霈F(xiàn)屏幕。因為沒有從 Logger 中刪除控制臺處理程序,所以堆棧溢出仍將出現(xiàn)在控制臺上。

      發(fā)生運行時異常時,可能要做許多工作來更改發(fā)生的問題。該代碼的大部分都是 Logging Handler,但是,要執(zhí)行更改,就必須細分 ThreadGroup ,重寫 uncaughtException() ,然后在該線程組中執(zhí)行您的線程。不過,讓我們通過只安裝 Thread.UncaughtExceptionHandler ,來看一看 Tiger 的處理方式。

      使用 UncaughtExceptionHandler 的定制行為

      對于 Tiger, Thread 類定義中添加了一個新的公共內(nèi)部類 UncaughtExceptionHandler ,更完整的名稱為 Thread.UncaughtExceptionHandler (其他類訪問內(nèi)部類時需要使用完整名稱)。接口的定義是一個方法,如圖 7 中所示:

      清單 7. UncaughtExceptionHandler 的定義

    public interface Thread.UncaughtExceptionHandler {
     public void uncaughtException(Thread, Throwable);
    }

      您可能沒有注意到,清單 7 中的方法與我們前面重寫的 ThreadGroup 的方法相同。實際上,現(xiàn)在由 ThreadGroup 類實現(xiàn)該接口。

      新的內(nèi)部類可以幫助我們了解下列兩對新方法,并有助于我們在 Thread 中使用它們:

    getUncaughtExceptionHandler() 和 setUncaughtExceptionHandler() 。
    getDefaultUncaughtExceptionHandler() 和 setDefaultUncaughtExceptionHandler() 。

      第一對方法是 getUncaughtExceptionHandler() 和 setUncaughtExceptionHandler() ,它們允許您為當前線程及其后代定制行為,從而允許二十或更多的線程擁有自己的定制行為。不過,您更可能使用第二對方法 getDefaultUncaughtExceptionHandler() 和 setDefaultUncaughtExceptionHandler() 。如果使用第二對方法設置默認處理程序,那么沒有自己的異常處理程序的所有線程都將使用默認處理程序。

      聽起來好像很簡單。為了進行說明,清單 8 轉(zhuǎn)換了 清單 3 中的 ThreadGroup 友好的程序,使用新的 UncaughtExceptionHandler 接口:

    清單 8. UncaughtExceptionHandler 示例

    public class HandlerDump {
     public static void main(String args[]) throws Exception {
      Thread.UncaughtExceptionHandler handler = new LoggingThreadGroup("Logger");
      Thread.currentThread().setUncaughtExceptionHandler(handler);
      System.out.println(1 / 0);
     }
    }

      該程序只是將 LoggingThreadGroup 重用為 UncaughtExceptionHandler ,并沒有創(chuàng)建新的處理程序?qū)崿F(xiàn)。請注意,與原來的代碼相比,新代碼要簡潔得多。

      其他線程更改

      Thread 類不僅支持使用 Tiger 添加的未捕獲異常處理程序,它還支持使用 getAllStackTraces() 獲得所有有效線程的堆棧跟蹤,或者支持使用 getStackTrace() 來只獲得當前線程的堆棧跟蹤。這兩種堆棧跟蹤都返回類型為 java.lang.StackTraceElement 的對象, java.lang.StackTraceElement 是 Java 1.4 平臺中添加的一個類,它可以讓您生成自己的堆棧跟蹤。同時,Java 5 平臺新添加的功能是一個惟一線程標識符(可以使用 getId() 獲得該標識符)和一個新的 Thread.State 類,以及與該類相關(guān)的 getThreadState() 方法。最后一個線程更改是一個狀態(tài)枚舉表,該表是用來監(jiān)視系統(tǒng)狀態(tài),而不是用來同步狀態(tài)的。

      結(jié)束語

      像添加未捕獲的異常處理程序這樣的簡單庫更改,可以極大地增加原代碼的可理解性。雖然在線程組級別上,新的庫代碼的功能與原來庫代碼的相同,但新模型中的易用性和靈活性遠遠超出了將代碼調(diào)整為更新的方式所需的時間。當然,老方法仍然可以使用,但最好將代碼更新為最新的庫功能。

    ---------------------------------------------------------------------------------------------------------------------------------
    說人之短,乃護己之短。夸己之長,乃忌人之長。皆由存心不厚,識量太狹耳。能去此弊,可以進德,可以遠怨。
    http://www.tkk7.com/szhswl
    ------------------------------------------------------------------------------------------------------ ----------------- ---------
    posted on 2009-01-16 15:16 宋針還 閱讀(192) 評論(0)  編輯  收藏 所屬分類: JAVA
    主站蜘蛛池模板: 久久91亚洲人成电影网站| 污污网站18禁在线永久免费观看| 亚洲综合亚洲国产尤物| 亚洲成年看片在线观看| 欧美好看的免费电影在线观看| 国产免费一区二区三区免费视频| 中文字幕无码精品亚洲资源网久久| 亚洲乱码精品久久久久..| 国产真实伦在线视频免费观看| 国产成人精品免费视频大全麻豆| 成人国产精品免费视频| 黄人成a动漫片免费网站| 亚洲欧美日韩综合久久久久| 亚洲精品无码久久毛片波多野吉衣 | 91福利视频免费观看| 成人免费网站久久久| 亚洲AV无码AV日韩AV网站| 亚洲国产精品综合一区在线| 亚洲av中文无码乱人伦在线咪咕| 亚洲欧洲精品成人久久奇米网| 国产人妖ts在线观看免费视频| 人妻视频一区二区三区免费| 国产成在线观看免费视频| 8888四色奇米在线观看免费看| 日韩视频在线观看免费| 国产免费AV片在线观看| a级毛片毛片免费观看久潮喷| 久久www免费人成精品香蕉| 深夜免费在线视频| 无码的免费不卡毛片视频| 免费国产草莓视频在线观看黄| 亚洲国产成人AV网站| 国产精品日本亚洲777| 国产成人久久精品亚洲小说| 色天使色婷婷在线影院亚洲| 亚洲av无码专区首页| 亚洲精品成a人在线观看夫| 亚洲人成在线播放| 亚洲国产精品VA在线观看麻豆| 美女视频黄的全免费视频网站| 97免费人妻无码视频|