从 UncaughtExceptionHandler 中重新执行任务?
Posted
技术标签:
【中文标题】从 UncaughtExceptionHandler 中重新执行任务?【英文标题】:Reexecute task from within UncaughtExceptionHandler? 【发布时间】:2011-06-04 03:33:35 【问题描述】:我看到了一些类似的讨论,但没有具体回答我的问题。当线程由于未捕获的异常而死亡时,我想重新启动任务。在即将死去的线程上设置的 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;
);
有没有更好或更安全的方法来做到这一点?
谢谢!
【问题讨论】:
【参考方案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);
【讨论】:
threadMap 只是为了让我得到与异常对应的 Thread 的 Monitor/Runnable。 restartMax 只是为了避免无限重启立即遇到一些持久错误的线程。这种机制旨在从一些尚未明确处理的临时异常中恢复。【参考方案2】:您的代码示例无法完成您尝试解决的工作。传递给 ThreadFactory 的可运行对象不是您的任务可运行对象,而是 ThreadPoolExecutor 使用的内部可运行对象。
您可能需要考虑重写 afterExecute() 方法。此方法将始终被调用,第一个参数将是您的可运行文件,第二个(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
【讨论】:
是的,我立即遇到了那个确切的问题。目前我正在使用传统的新 Thread/setUncaughtExceptionHandler/start 序列。您无法从 Thread 访问 Runnable 似乎既奇怪又短视。我会研究你的建议。我没有使用 FutureTask 也没有提交,所以这应该可以。谢谢! 即使线程是通过传入的 runnable 创建的,请注意它只是触发线程创建的 第一个 任务。线程将长期存在并运行多个任务。因此,您将无法可靠地获取导致 RuntimeException 的实际可运行对象。以上是关于从 UncaughtExceptionHandler 中重新执行任务?的主要内容,如果未能解决你的问题,请参考以下文章