【问题标题】:Maintaining a single executor service and shutting it down appropriately维护单个执行器服务并适当地关闭它
【发布时间】:2015-07-15 12:08:27
【问题描述】:

我的应用程序需要异步完成某项工作,所以我求助于执行器框架。如果某个外部接口关闭(供应商可能会备份一段时间,例如 30 分钟),则该作业(Runnable)预计会运行。

考虑到这个问题,我认为我应该维护一个固定编号的预定执行器服务。当我上面所说的接口短暂关闭时执行这些工作的核心线程的数量(作为我需要线程池的类中的static 变量)。我也不认为我应该为处理此类作业的每个需要创建一个执行器(单个计划的线程池执行器),并在作业运行后关闭,因为这会破坏我的目的,不是吗?因为这可能意味着在备份时间内为每个作业保留一个线程,这对我来说听起来很可怕。

但是,如果我要维护这样一个 executor 服务,我什么时候会关闭 executor?我知道执行器一旦关闭就不能被重用,而不关闭执行器并保持线程处于活动状态可能会阻止 JVM 关闭。我该怎么办?

我最后的声明是基于Effective Java 2nd edition

这里是如何告诉执行者优雅地终止(如果你 如果不这样做,您的虚拟机可能不会退出):

executor.shutdown();

【问题讨论】:

    标签: java multithreading scheduledexecutorservice


    【解决方案1】:

    这个作业(一个 Runnable)预计会在某个外部 接口已关闭(供应商可能会备份一段时间,例如 30 分钟)。

    以上是您的要求。现在解决方案完全取决于如何处理上述情况。

    • 触发器或事件监听器:如果你有一些触发器或事件监听器可以在发现某个外部接口关闭时调用,那么在那个触发的代码或事件中监听器,你可以创建一个ExecutorService,执行你所有的任务(你可以选择在固定或池化线程池上),然后在所有任务完成后,你可以关闭ExecutorService
      在这种情况下,最好创建一个ExecutorService,执行任务并将其关闭。无需长时间运行ExecutorService

    • 跟踪或定期检查:如果您必须定期跟踪或检查某个外部接口是否关闭,那么我认为您可以有一个ScheduledThreadPoolExecutor 实现在固定时间间隔后进行检查某个外部接口是否已关闭,如果已关闭,则执行所有任务。在这种情况下,您不会关闭您的 ExecutorService,它会一直运行。

    P.S.:Trigger 和 Track 是我自己的约定,我将其用作一个词,所以请用技术词来推断。

    我了解执行程序一旦关闭就不能重复使用,而 不关闭执行程序并保持线程处于活动状态可能 防止JVM关闭。

    是的,执行程序一旦关闭就不能重复使用。
    不,正在运行的 ExecutorService 不会阻止您关闭 JVM,但是一旦 JVM 关闭,该 ExecutorService 实例及其线程池将停止并销毁。

    【讨论】:

    • 添加了来自Effective Java 2nd edition 的引用,这让我认为 JVM 退出会在 OP 中出现问题。所以也许我误解了它?你能澄清一下吗?
    • 我的案例有点像“Track”风格,尽管也可以说是“Trigger”风格。不涉及定期检查,但我想以 60 秒的预定延迟运行作业。在这种情况下,您会推荐一个(静态)ExecutorService 吗?
    • JVM 关闭确实要复杂得多,因为有关闭钩子等,所以在很多情况下 JVM 关闭可能会在关闭之前等待,但在“Effective Java”中的这种特殊情况下,我猜想(我不确定,他们没有详细说明)他们可能指的是执行程序服务正在运行并且执行程序运行的线程很少。但实际上执行器的所有线程都不太可能运行,当线程在执行器线程池中时,它们处于等待状态并且不活动。任何非守护进程活动线程都可以让 JVM 等待。
    • 既然“Effective Java”已经提到所以应该有一点,但没有太多的澄清。如果这是真的,那么试试这个 - 在一个简单的 Java 程序中,创建一个执行器服务并且不要关闭执行器,然后你会看到 JVM 还没有完成,现在你可以通过 CTRL+C 或关闭按钮关闭 JVM ,您将看到 JVM 已关闭。所以,这意味着JVM关闭。我们的应用程序中也有执行器服务,我们从未见过 JVM 关闭因为执行器服务而停止。
    • 由于您的要求是一个连续的过程,我会说在您的服务器启动时,产生一个新线程并在那里创建执行程序服务及其相关代码。这样你就不需要有一个静态的执行器,并且当同一个JVM实例运行时,也不可能再次调用执行器的代码。
    猜你喜欢
    • 2020-08-07
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多