从UncaughtExceptionHandler中重新执行任务?

时间:2011-01-05 16:41:45

标签: java multithreading

我看到过这些问题的一些讨论,但不是我问题的具体答案。我想在线程因未捕获的异常而死亡时重新启动任务。从垂死线程上设置的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;
    }           
});

有更好的方法或更安全的方法吗?

谢谢!

2 个答案:

答案 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
        }
    }
}