国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

馴服 Tiger:線程中的默認異常處理

2019-11-18 12:21:20
字體:
來源:轉載
供稿:網友

  跟蹤無法預期的運行時異常可能是一件又慢又費力的事情,只獲得默認線程名稱和堆棧跟蹤通常是不夠的。在馴服 Tiger 這一期專欄中,java 開發人員 John Zukowski 向您展示了如何通過替代默認行為來定制輸出。他還對比了通過細分 ThreadGroup 定制輸出的老方法與通過提供自己的 UncaughtExceptionHandler 定制輸出的新方法。
  
  雖然我們不想創建在無法預期時拋出運行時異常的程序,但這種情況還是會發生——尤其是第一次運行復雜程序時。通常是使用默認行為、打印堆棧溢出和結束線程的生命來處理這些異常。
  
  從哪里發現默認行為?每個線程都屬于一個由 java.lang.ThreadGroup 類表示的線程組。顧名思義,線程組答應您將線程組合在一起。您可能是為了方便而將線程組合,例如,一個線程池中的所有線程都屬于組 X,而另一個池的所有線程則屬于組 Y,或者是為了訪問控制而將線程進行組合。組 X 中的線程無權訪問或改變組 Y 中的線程,除非它們都在同一線程組內(或在一個子組內)。
  
  在 Tiger 之前,ThreadGroup 類提供了一種處理未捕捉異常的方法:ThreadGroup 的 uncaughtException() 方法。假如異常不是 ThreadDeath,則將線程的名稱和堆棧回溯(stack backtrace)發送到 System.err。但是 Tiger 添加了另一種方法:Thread.UncaughtExceptionHandler 接口。細分 ThreadGroup 或安裝該新接口的實現都答應您更改默認行為。我們將對 Tiger 之前和之后提供的方法都進行研究。
  
  使用 ThreadGroup 的定制行為
  發生未捕捉的異常時,默認行為是將堆棧溢出打印輸出到系統錯誤(System.err)中,如清單 1 中所示。不需要使用任何命令參數來啟動程序。
  
  清單 1. 線程溢出示例
  
  public class SimpleDump {
   public static void main(String args[]) {
    System.out.PRintln(args[0]);
   }
  }
  
  不使用任何參數運行該程序將生成清單 2 中的輸出。盡管它不是一個很長的堆棧跟蹤,但它是一個完整的堆棧跟蹤。
  
  清單 2. 默認線程溢出輸出
  
  Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
      at SimpleDump.main(SimpleDump.java:3)
  
  正如 Java 平臺的許多東西一樣,假如不喜歡默認行為,您可以對其進行更改。在 Java 平臺的 Tiger 版以前的版本中,不能替代所有線程的默認行為,但是可以創建一個新的 ThreadGroup,并更改在該組內創建的任何線程的默認行為。您可以重寫 uncaughtException(Thread t, Throwable e) 方法來定制該行為。然后,當發生未預料的運行時異常時,該線程組內創建的任何線程都將獲得新的行為。不過,最好是修復基礎問題,我將提供一個簡單的示例,說明更改默認行為所必需的步驟。清單 3 展示了將執行代碼放入新線程的調整過的測試程序:
  
  清單 3. 調整過的線程溢出示例
  
  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 類是一個新的內容,清單 4 中顯示了它的定義。為了進行說明,通過重寫 uncaughtException() 方法實現的非凡行為將在一個彈出窗口中顯示該異常,這項操作是在非凡 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);
   }
  }
  
  這里創建的定制 Handler 的類型為 LoggingWindowHandler,該類型的定義在清單 5 中。處理程序使用了一個支持類 LoggingWindow,該類將異常顯示在屏幕上。清單 6 中顯示了該類的定義。Handler 的 public void publish(LogRecord record) 方法實現了一些重要操作。其余操作大部分只與配置有關。
  
  清單 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);
     }
    });
   }
  }
  
  發生運行時異常時,可能要做許多工作來更改發生的問題。該代碼的大部分都是 Logging Handler,但是,要執行更改,就必須細分 ThreadGroup,重寫 uncaughtException(),然后在該線程組中執行您的線程。不過,讓我們通過只安裝 Thread.UncaughtExceptionHandler,來看

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 乌海市| 汕头市| 福贡县| 普宁市| 民乐县| 永宁县| 美姑县| 长宁区| 泸定县| 三江| 贡山| 榆中县| 康马县| 台湾省| 平乡县| 扎鲁特旗| 七台河市| 滦平县| 申扎县| 和田市| 文登市| 延庆县| 田东县| 富裕县| 巴塘县| 莎车县| 朔州市| 密山市| 平阳县| 新乡市| 马尔康县| 油尖旺区| 三原县| 金溪县| 丹阳市| 安龙县| 卓尼县| 满洲里市| 泗洪县| 虞城县| 临邑县|