2008-11-16 61 views
4

我正在開發一個J2ME項目,該項目爲許多任務(例如下載HTTP內容)生成工作線程。基本的線程佈局與大多數Java應用程序類似 - 有一個主UI線程和工作線程派生出來在幕後執行。我的問題是什麼是處理工作線程中發生異常的最佳方法?處理單獨線程中拋出異常的最佳方法是什麼?

我通常堅持設計原理,大多數例外應儘可能滲透。當我編寫單線程應用程序時,我通常會將例外一直滲透到UI層,然後在錯誤對話框中向用戶報告它們。是否有類似的多線程應用程序的做法?對我來說最直觀的是在Thread.run()中捕獲異常,然後在UI線程上調用invokeLater以在對話框中報告它。我在這裏看到的問題是,在工作線程過早死掉之後,這種方法並沒有真正通知UI線程有錯誤。可以這麼說,我沒有看到一個清晰的方法來拋出異常。

感謝, 安迪

回答

7

你不應該果醬UI代碼到你的員工!

/** 
* TWO CHOICES: 
* - Monitor your threads and report errors, 
* - setup a callback to do something. 
*/ 
public class ThreadExceptions { 

    /** Demo of {@link RunnableCatch} */ 
    public static void main(String[] argv) throws InterruptedException { 
     final Runnable bad = new NaughtyThread(); 
     // safe1 doesnt have a callback 
     final RunnableCatch safe1 = new RunnableCatch(bad); 
     // safe2 DOES have a callback 
     final RunnableCatch safe2 = new RunnableCatch(bad, new RunnableCallback() { 
      public void handleException(Runnable runnable, Exception exception) { 
       System.out.println("Callback handled: " + exception.getMessage()); 
       exception.printStackTrace(); 
      } 

     }); 
     final Thread t1 = new Thread(safe1, "myThread"); 
     final Thread t2 = new Thread(safe2, "myThread"); 
     t1.start(); 
     t2.start(); 
     t1.join(); 
     t2.join(); 
     if (safe1.getException() != null) { 
      System.out.println("thread finished with exceptions"); 
      safe1.getException().printStackTrace(); 
     } 
     System.out.println("done"); 
    } 


} 

/** Throws an exception 50% of the time */ 
class NaughtyThread implements Runnable { 
    public void run() { 
     try { 
      if (Math.random() > .5) { 
       throw new RuntimeException("badness"); 
      } 
     } finally { 
      System.out.println("ran"); 
     } 
    } 
} 

/** Called when an exception occurs */ 
interface RunnableCallback { 
    void handleException(Runnable runnable, Exception exception); 
} 

/** 
* Catches exceptions thrown by a Runnable, 
* so you can check/view them later and/or 
* deal with them from some callback. 
*/ 
class RunnableCatch implements Runnable { 

    /** Proxy we will run */ 
    private final Runnable _proxy; 

    /** Callback, if any */ 
    private final RunnableCallback _callback; 

    /** @guarded-by(this) */ 
    private Exception _exception; 

    public RunnableCatch(final Runnable proxy) { 
     this(proxy, null); 
    } 

    public RunnableCatch(final Runnable proxy, RunnableCallback target) { 
     _proxy = proxy; 
     _callback = target; 
    } 

    public void run() { 
     try { 
      _proxy.run(); 
     } catch (Exception e) { 
      synchronized (this) { 
       _exception = e; 
      } 
      if (_callback != null) { 
       _callback.handleException(_proxy, e); 
      } 
     } 
    } 

    /** @return any exception that occured, or NULL */ 
    public synchronized Exception getException() { 
     return _exception; 
    } 
} 
+0

感謝Stuph。這更有意義。你的例子中的一個簡短問題:同步(this)塊是否真的有必要圍繞_exception賦值?我的印象是對象分配是原子的。 – Andy 2008-11-16 04:55:23

0

除了Stuph給出的另一個選項是在線程本地設置異常。如果在該異常被清除之前發生另一個異常,則會發生斷言。這至少會讓某人有機會注意到這個異常並對其進行處理。

相關問題