我想处理ThreadPoolExecutor#afterExecute()
方法中工作线程抛出的exeptions。目前我有这段代码:
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
为什么参数Throwable t
null
位于afterExecute()
?它不应该是SQLException
实例吗?
答案 0 :(得分:8)
这实际上是预期的行为。
引用afterExecute
Javadoc:
如果非null,则Throwable是未捕获的RuntimeException或Error,导致执行突然终止。
这意味着throwable实例将为RuntimeException
或Error
,不已选中Exception
。由于SQLException
是已检查的例外,因此不会将其传递给afterExecute
。
此处还有其他事情(仍在引用Javadoc):
注意:当任务明确地或通过诸如submit之类的方法包含在任务(例如
FutureTask
)中时,这些任务对象会捕获并维护计算异常,因此它们不会导致突然终止,并且内部异常不会传递给此方法。
在您的示例中,由于您要提交FutureTask
,因此任务包含在Callable
中,因此您就是这种情况。即使在您更改代码时也会抛出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); }
答案 1 :(得分:1)
这是另一种方法。从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..");
}
}
}
afterExecute的用法用途不同。
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
反过来失败并突然终止。