Java“终结”线程异常

发布于 2024-12-11 14:15:27 字数 1306 浏览 0 评论 0原文

我正在使用多个线程对大型数据集进行一些繁重(且容易出错)的处理。我要求所有线程都完成执行,无论它们是抛出异常还是正常终止(不返回任何值),然后程序才能继续。我使用 CountDownLatch 来实现此目的,并使用 ExecutorService 来实际运行作业。我希望工作线程(为了便于论证,我们将其称为 JobManager-s)即使抛出异常也能通知闩锁。 JobManager 可能需要一秒到一小时才能完成,并且可能随时失败。这个想法是在抛出异常时调用 JobManager 的“finalizer”方法。现在,ExecutorService 喜欢捕获异常或隐藏它不捕获的异常的真实来源。我有一些解决这个问题的方法,但都不是令人满意的:

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

  2. 使用自定义ExecutorService并重写afterExecute(Runnable r, Throwable t)方法。这与 1 存在相同的问题。

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

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

非常感谢任何建议。

I am using several threads to do some heavy (and error-prone) processing on a large data set. I require all threads to finish execution, regardless of whether they throw an exception or terminate normally (no value is returned), before the program can continue. I am using a CountDownLatch to achieve this, and an ExecutorService to actually run the jobs. I want the worker threads (let's call them JobManager-s for the sake of argument) to notify the latch even if they throw an exception. A JobManager can take anywhere between a second and an hour to complete, and may fail at any time. The idea is to invoke the "finalizer" method of JobManager if an exception is thrown. Now, the ExecutorService likes to catch exceptions or to conceal the true origin of the ones it does not. I have though of a few ways around this, neither of which is satisfactory:

  1. Use ExecutorService#execute(Runnable r) rather than submit(Runnable r). I can do that since I do not care about the return value of the JobManager. I have provided a custom ThreadFactory, which attaches an UncaughtExceptionHandler to each newly created thread. The problem with this approach is that when UncaughtExceptionHandler#uncaughtException(Thread t, Throwable e) is invoked, t's Runnable is of type ThreadPoolExecutor$Worker, and not of type JobManager, which prevents me from invoking the "finalizer" method.

  2. Use a custom ExecutorService and override the afterExecute(Runnable r, Throwable t) method. This suffers from the same problem as 1.

  3. Wrap the whole JobManager#doWork() in a catch statement and use the return value to indicate if an exception was thrown. I can then submit the jobs and use FutureTask#get() to decide if an exception was thrown. I do not like this solution because I feel return codes the wrong tool when you have an elaborate exception mechanism. Moreover, get() will wait (unless interrupted), which means I cannot handle errors in other threads immediately.

  4. Get rid of the CountDownLatch. Store all Futures in a list and repeatedly poke in until I am satisfied with the states. This might work, but feels like a dirty hack.

Any suggestions are greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

木槿暧夏七纪年 2024-12-18 14:15:27

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

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

As far as I understand, you can use a simple try-finally block:

public class JobManager {
    public void doWork() {
        try {
            ...
        } finally {
            countDownLatch.countDown();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文