我看到过这些问题的一些讨论,但不是我问题的具体答案。我想在线程因未捕获的异常而死亡时重新启动任务。从垂死线程上设置的UncaughtExceptionHandler中调用pool.execute(runnable)是否安全?
理想情况下,如果throwable是RuntimeException,我想将runnable重新提交给池,例如
pool = Executors.newFixedThreadPool(monitors.size(), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
threadMap.put(thread, (Monitor)r);
thread.setName(((Monitor)r).getClusterName() + "-monitor");
thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread th, Throwable t) {
logger.error("Uncaught exception in thread: " + th.getName(), t);
if (t instanceof RuntimeException) {
Monitor m = threadMap.get(th);
if (m != null && m.runCount() < restartMax) {
logger.error("Restarting monitor due to uncaughtException: " + m.getClusterName());
pool.execute(m);
} }
}
});
return thread;
}
});
有更好的方法或更安全的方法吗?
谢谢!
答案 0 :(得分:1)
最安全的选择是只抛出一个致命的运行时异常。如果可以安全地忽略运行时异常,为什么它没有被捕获并继续?
看起来您的线程映射就像一个ThreadLocal,看来一旦一个任务使用了所有的restartMax,它就永远不会再次重启任务?
我这样做的方法是包装执行的Runnable。
public void submit(final Runnable runnable, final int restartMax) {
pool.submit(new Runnable() {
public void run() {
for(int i=0;i<restartMax;i++)
try {
runnable.run();
break;
} catch (Exception e) {
log.error("Exception", e);
}
}
}
}
答案 1 :(得分:0)
您的代码示例将无法完成您尝试解决的问题。传递给ThreadFactory的runnable不是你的任务可运行的,而是ThreadPoolExecutor使用的内部runnable。
您可能需要考虑改写afterExecute()方法。将始终调用此方法,第一个参数将是您的runnable,第二个(Throwable)参数将包含未捕获的异常。但是,如果任务由FutureTask显式包装或通过submit()间接包装,则afterExecute()将不报告异常。因此,afterExecute()仅适用于通过execute()提交。
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t != null) {
Monitor m = (Monitor)r;
if (m.runCount() < restartMax) {
logger.error("Restarting monitor due to uncaughtException: "
+ m.getClusterName());
execute(m); // exception handling omitted
}
}
}