Java在异常上“敲定”线程

时间:2011-10-25 17:05:13

标签: java multithreading

我正在使用多个线程对大型数据集执行一些繁重(且容易出错)的处理。在程序可以继续之前,我要求所有线程完成执行,无论它们是抛出异常还是正常终止(没有返回值)。我使用CountDownLatch来实现此目的,并使用ExecutorService来实际运行作业。我希望工作线程(让我们称之为JobManager - s为了参数)通知锁存器,即使它们抛出异常。 JobManager可能需要一到两个小时才能完成,并且可能随时失败。如果抛出异常,我们的想法是调用JobManager的“终结器”方法。现在,ExecutorService喜欢捕捉异常或隐藏其不存在的真实起源。我有几种解决方法,但都不令人满意:

  1. 使用ExecutorService#execute(Runnable r)而不是submit(Runnable r)。我可以这样做,因为我不关心JobManager的返回值。我提供了一个自定义ThreadFactory,它为每个新创建的线程附加UncaughtExceptionHandler。这种方法的问题在于,当UncaughtExceptionHandler#uncaughtException(Thread t, Throwable e)被调用时,t的{​​{1}}类型为Runnable,而不是类型ThreadPoolExecutor$Worker,这会阻止我从调用“终结者”方法。

  2. 使用自定义JobManager并覆盖ExecutorService方法。这与1的问题相同。

  3. 将整个afterExecute(Runnable r, Throwable t)包装在JobManager#doWork()语句中,并使用返回值指示是否抛出了异常。然后我可以catch作业并使用submit来决定是否抛出异常。我不喜欢这个解决方案,因为当你有一个精心设计的异常机制时,我觉得返回代码是错误的工具。此外,FutureTask#get()将等待(除非被中断),这意味着我无法立即处理其他线程中的错误。

  4. 摆脱get()。将所有CountDownLatch存储在列表中并反复戳入,直到我对状态感到满意为止。这可能有用,但感觉就像是一个肮脏的黑客。

  5. 非常感谢任何建议。

1 个答案:

答案 0 :(得分:4)

据我了解,您可以使用简单的try - finally块:

public class JobManager {
    public void doWork() {
        try {
            ...
        } finally {
            countDownLatch.countDown();
        }
    }
}