簡體   English   中英

如何在FutureTask中捕獲異常

[英]How to catch exceptions in FutureTask

在發現在Java 1.6(和Eclipse Executors.newCachedThreadPool()上的Executors.newCachedThreadPool()運行的FutureTask吞噬了Runnable.run()方法中的異常之后,我試圖想出一種方法來捕獲這些異常而不添加throw / catch我所有的Runnable實現。

API建議覆蓋FutureTask.setException()應該有助於:

導致此未來報告ExecutionException,並將給定的throwable作為其原因,除非已設置或已取消此Future。 在計算失敗時,run方法在內部調用此方法。

但是,似乎沒有調用此方法(使用調試器運行顯示FutureTask捕獲異常,但未setException )。 我寫了以下程序來重現我的問題:

public class RunTest {
    public static void main(String[] args) {
        MyFutureTask t = new MyFutureTask(new Runnable() {

            @Override
            public void run() {
                throw new RuntimeException("Unchecked exception");

            }
        });

        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(t);
    }
}

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void setException(Throwable t) {
        super.setException(t);
        System.out.println("Exception: " + t);
    }
}

我的主要問題是:如何捕獲FutureTask中引發的異常? 為什么不調用setException

另外我想知道為什么FutureTask不使用Thread.UncaughtExceptionHandler機制,有什么理由嗎?

setException可能不是用於覆蓋,而是用於在需要時將結果設置為異常。 你想要做的是覆蓋done()方法並嘗試獲得結果:

public class MyFutureTask extends FutureTask<Object> {

    public MyFutureTask(Runnable r) {
        super(r, null);
    }

    @Override
    protected void done() {
        try {
            if (!isCancelled()) get();
        } catch (ExecutionException e) {
            // Exception occurred, deal with it
            System.out.println("Exception: " + e.getCause());
        } catch (InterruptedException e) {
            // Shouldn't happen, we're invoked when computation is finished
            throw new AssertionError(e);
        }
    }
}

您是否嘗試過使用UncaughtExceptionHandler

  • 您需要實現UncaughtExceptionHandler接口。
  • 要為池線程設置UncaughtExceptionHandler ,請在Executor.newCachedThreadPool(ThreadFactory)調用中提供ThreadFactory
  • 您可以通過setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)為創建的線程設置UncaughtExceptionHandler

使用ExecutorService.execute提交任務,因為只有從使用execute提交的任務拋出的異常才能使其成為未捕獲的異常處理程序。 對於使用ExecutorService.submit提交的任務,任何拋出的異常都被視為任務返回值的一部分。 如果使用submit提交的任務以異常終止,則在調用Future.get時會Future.get ,包含在ExecutionException

一個更好的解決方案: Java FutureTask完成檢​​查

當調用futureTask.get()來檢索計算結果時,如果底層Runnable / Callable引發異常,它將拋出異常(ExecutionException)。

ExecutionException.getCause()將返回Runnable / Callable拋出的異常。

如果Runnable / Callable被取消,它也會拋出一個不同的異常。

我查看了FutureTask的源代碼,但無法找到調用setException位置。
有一個innerSetException從方法FutureTask.Sync (內部類的FutureTask ),其被稱為在的情況下Throwable由run方法拋出。 此方法也在setExceptionsetException
所以像javadoc這樣的接縫不正確(或者很難理解......)。

有三種標准方式和一種即興方式。 1.使用UncaughtExceptionHandler,將創建的線程的UncaughtExceptionHandler設置為

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}

*但是限制是它捕獲線程拋出的異常,但是在未來任務的情況下,它被吞噬。 2.在使用專門為此目的提供的鈎子制作自定義threadpoolexecutor之后使用afterExecute 查看ThreadpoolExecutor的代碼,通過submit> execute(有一個workQueue, workQueue.offer ),將任務添加到工作隊列中

   final void runWorker(Worker arg0) {
  Thread arg1 = Thread.currentThread();
  Runnable arg2 = arg0.firstTask;
  ..
     while(arg2 != null || (arg2 = this.**getTask()**) != null) {
        arg0.lock();
        ..
        try {
           this.beforeExecute(arg1, arg2);
           Object arg4 = null;
           try {
              arg2.run();
           } catch (RuntimeException arg27) {
             ..
           } finally {
              this.**afterExecute**(arg2, (Throwable)arg4);
           }

  }

getTask() {..
 this.workQueue.**poll**();
..}
  1. 然后,第三個是在調用方法中使用簡單的try catch但是你不能在這里捕獲異常。

  2. 解決方法是從TaskFactory的調用方法調用所有調用方法,TaskFactory是一個釋放callables的工廠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM