【问题标题】:Catching Exceptions from (ExecutorService) CachedThreadPool从 (ExecutorService) CachedThreadPool 中捕获异常
【发布时间】:2013-04-10 23:21:44
【问题描述】:

我们正在使用通过 ExecutorService#newCachedThreadPool 创建的 CachedThreadPool。 (Java 1.6)。我们在代码的其他地方遇到错误:“无法创建新的本机线程”,我们已将其诊断为内存不足问题。当这个问题发生时,我们调用提交的代码块(我们使用提交,而不是执行)会变慢。我们怀疑 ThreadPool 在尝试创建新线程来处理任务时遇到了同样的问题“无法创建新的本地线程”,但我们不能确定。

有没有办法从 ExecutorService 内部捕获异常? 100% 清楚,我说的不是交给 ExecutorService 的任务,而是来自 ExecutorService 本身。

【问题讨论】:

  • 也许你应该做一个线程转储并查看所有这些线程的去向。这不应该发生。
  • 这绝对是系统负载问题。我知道它不应该去。这是由于下游依赖失败并且我们有重试逻辑。线程全部排队等待重试。

标签: java executorservice


【解决方案1】:

Executors.newCachedThreadPool 创建一个具有无限最大线程池大小的ThreadPoolExecutor(注意ThreadPoolExecutor 构造函数的第二个参数):

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

也就是说,如果你提交任务的速度快于消耗速度,那么每个新任务都会创建新线程,最终会达到系统限制并抛出“无法创建新的本地线程”异常。

要解决这个问题,你需要更改ThreadPoolExecutor的配置:

  1. 使用合理的 ThreadPoolExecutor。
  2. ThreadPoolExecutor 用尽时选择适当的拒绝策略。

例如:

ExecutorService executorService = new ThreadPoolExecutor(5,200,
                          60L, TimeUnit.SECONDS,
                          new ArrayBlockingQueue(1000),
                          Executors.defaultThreadFactory(),
                          new ThreadPoolExecutor.CallerRunsPolicy());

请阅读JavaDocs了解配置详情。

【讨论】:

  • 谢谢。我一直在研究文档,我明白为什么会发生这种情况,但我想知道是否有任何方法可以捕捉到错误?我必须编写自己的 ThreadFactory 吗?
  • @JohnHinnegan 我不明白您为什么要捕获该错误。我认为将无限池大小的线程池用于长时间运行的任务是错误的设计。
  • 它们运行时间不长。我并不反对无限池是有风险的,或者完全是错误的。但是如果主机上的其他东西正在运行,固定池可能会出现这个问题。我正在尝试在我的系统中建立强大的监控,但这个错误突然出现并且在我们系统的一部分中未被检测到。我知道这是错误,因为我们在其他地方发现了它(显然它对 JVM 来说是全局的)。当您回答时,我不明白 RejectedExecutionHandler 是什么。我认为这回答了我的问题。我想我可以实现其中之一来处理异常。
【解决方案2】:

您可以使用实现 Runnable 的自定义类,其中包含一组异常,如下所示:

public class MyRunnable implements Runnable {
    private List<Exception> exceptions;

    ...

    public void addException(Exception e) { ... }
    public void getExceptions(){ ... }
}

在所有可运行对象完成执行后,您可以检查它们内部的异常并抛出另一个异常作为响应。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-09
    • 2013-07-13
    • 2016-10-31
    • 2011-05-07
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多