![](/img/trans.png)
[英]I cannot catch the exceptions of the FutureTask.get() method. The FutureTask is launched by a Spring TaskExecutor
[英]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方法拋出。 此方法也在setException
中setException
。
所以像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**();
..}
然后,第三個是在調用方法中使用簡單的try catch但是你不能在這里捕獲異常。
解決方法是從TaskFactory的調用方法調用所有調用方法,TaskFactory是一個釋放callables的工廠。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.