8

ThreadPoolExecutor#afterExecute()メソッドでワーカースレッドによってスローされた例外を処理したい。私は、コードを実行した場合、私は出力を得るThreadPoolExecutorのafterExecute()で例外がnullになるのはなぜですか?

public class MyExecutor extends ThreadPoolExecutor { 

    public static void main(String[] args) { 
     MyExecutor threadPool = new MyExecutor(); 
     Task<Object> task = new Task<>(); 
     threadPool.submit(task); 
    } 

    public MyExecutor() { 
     super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4000)); 
    } 

    @Override 
    protected void afterExecute(Runnable r, Throwable t) { 
     super.afterExecute(r, t); 
     System.out.println("in afterExecute()"); 
     if (t != null) { 
      System.out.println("exception thrown: " + t.getMessage()); 
     } else { 
      System.out.println("t == null"); 
     } 
    } 

    private static class Task<V> implements Callable<V> { 

     @Override 
     public V call() throws Exception { 
      System.out.println("in call()"); 
      throw new SQLException("testing.."); 
     } 
    } 
} 

in call() 
in afterExecute() 
t == null 

なぜafterExecute()におけるパラメータThrowable tnullですが現在、私はこのコードを持っていますか? SQLExceptionインスタンスであってはなりませんか?

答えて

7

これは実際には予想される動作です。

null以外の場合は、Throwableのは、実行が突然終了させたキャッチされないのRuntimeExceptionまたはErrorは、次のとおりです。

afterExecute Javadocを引用。

これはスロー可能なインスタンスがRuntimeExceptionまたはErrorExceptionをチェックしていないことを意味します。 SQLExceptionはチェックされた例外ですので、afterExecuteには渡されません。

(まだJavadocを引用)他の何かここで起こってもあります:

注:アクションは、タスク(例えばFutureTaskをなど)を明示的または、そのようなこれらの提出などのメソッドを経由してで囲まれていた場合タスクオブジェクトは計算上の例外を捕捉して維持するため、突然終了することはなく、内部例外はこのメソッドに渡されません。あなたがCallableを提出しているので、あなたの例では

は、タスクがFutureTaskで囲まれているので、あなたは、このケースです。 RuntimeExceptionをスローするようにコードを変更した場合でも、afterExecuteには与えられません。 Javadocは参考のために、私はここにコピーしていますこの問題に対処するためのサンプルコードを与える:

protected void afterExecute(Runnable r, Throwable t) { 
    super.afterExecute(r, t); 
    if (t == null && r instanceof Future) { 
     try { 
     Object result = ((Future) r).get(); 
     } catch (CancellationException ce) { 
      t = ce; 
     } catch (ExecutionException ee) { 
      t = ee.getCause(); 
     } catch (InterruptedException ie) { 
      Thread.currentThread().interrupt(); // ignore/reset 
     } 
    } 
    if (t != null) 
     System.out.println(t); 
} 
+0

ありがとうございます。だから、チェックされた例外はすべてThreadPoolExecutorによって飲み込まれるだけですか?すべての例外処理はCallable#call()で行わなければなりませんか? –

+1

@ potato300私の編集を参照してください、特定の例で何か他のことが起こっています(私が最初に気付かなかったもの) – Tunaki

1

をこれはそれを行うための別の方法です。 afterExecuteの使用here

package com.autonomy.introspect.service; 

import java.sql.SQLException; 
import java.util.concurrent.*; 

public class MyExecutor extends ThreadPoolExecutor { 

    public static void main(String[] args) { 
     MyExecutor threadPool = new MyExecutor(); 
     Task<Object> task = new Task<Object>(); 
     Future<Object> futureTask = threadPool.submit(task); 
     try { 
      System.out.println(futureTask.get()); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } catch (ExecutionException e) { 
      System.out.println("exception thrown: " + e.getMessage()); 
     } 
    } 

    public MyExecutor() { 
     super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(4000)); 
    } 

    @Override 
    protected void afterExecute(Runnable r, Throwable t) { 
     super.afterExecute(r, t); 
     System.out.println("in afterExecute()"); 
     if (t != null) { 
      System.out.println("exception thrown: " + t.getMessage()); 
     } else { 
      System.out.println("t == null"); 
     } 
    } 

    private static class Task<V> implements Callable<V> { 

     @Override 
     public V call() throws Exception { 
      System.out.println("in call()"); 
      throw new SQLException("testing.."); 
     } 
    } 
} 

からヒントを取ることは、異なる目的のためのものです。

This class provides protected overridable beforeExecute(java.lang.Thread, 
java.lang.Runnable) and afterExecute(java.lang.Runnable, 
java.lang.Throwable) methods that are called before and after execution of 
each task. These can be used to manipulate the execution environment; for 
example, reinitializing ThreadLocals, gathering statistics, or adding log 
entries. Additionally, method terminated() can be overridden to perform any 
special processing that needs to be done once the Executor has fully 
terminated. 

If hook or callback methods throw exceptions, internal worker threads may 

が失敗し、突然終了します。

関連する問題