【问题标题】:How to shutdown and reinstantiate an Executor Service without loosing tasks如何在不丢失任务的情况下关闭和实例化 Executorservice
【发布时间】:2022-01-14 05:32:08
【问题描述】:

我不完全明白,我应该如何在一个应用程序中实现一个 ExecutorService,偶尔会执行一些任务。每个任务运行大约 15 分钟(更长的时间)。有时一天有 10 个任务,有时一整周都没有。

因此,如果队列中没有剩余任务,则在执行某些任务后,我想关闭执行程序,因为不再需要它,以便垃圾收集器可以完成其工作。 调用shutdown后,没有新任务排队到executor。

现在,我的问题是我必须确保所有任务都已完成。这意味着,在调用 shutdown 之后,我必须确保在提交新任务之前实例化一个新的 Executor Service。我必须等到旧的 Executor Service 关闭(或终止?)并启动一个新的。我应该如何实现这个?

这是我的方法:

// sync block to check for each task if a new Executor Service has to be created before submitting the task
synchronized (this) {
    // do I have to check both isSutdown and isTerminated?
    if (null == businessTaskExecutor || businessTaskExecutor.isShutdown() || businessTaskExecutor.isTerminated()) {
        // simply init a new one
        businessTaskExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
    } else if (businessTaskExecutor.isTerminating()) {
        // the termination process has started and is not done.
        // Do I have to wait for the old executor or can I simply init a new one without waiting?
        while (!businessTaskExecutor.isTerminated()) { }
        businessTaskExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
    }
}
Future<?> future = businessTaskExecutor.submit(() -> new BusinessTaskRunnable(businessTask));
if (future.isDone() && businessTaskExecutor.getQueue().isEmpty()) {
    businessTaskExecutor.shutdown();
    try {
        if (!businessTaskExecutor.awaitTermination(1, TimeUnit.HOURS)) {
            businessTaskExecutor.shutdownNow();
        }
    } catch (InterruptedException ex) {
        businessTaskExecutor.shutdownNow();
        Thread.currentThread().interrupt();
    }
}

解释:

如果执行程序为空/关闭/终止,我会启动一个新的,到目前为止一切顺利。 否则,如果执行器当前正在终止(因为调用了 shutdown),则执行器将不再接受任何任务。所以我等到它被终止,然后再启动一个新的。 之后我提交我的任务...... 如果队列中没有其他任务,我只会关闭执行程序。尽管我等了一个小时,但仍有可能有正在运行的任务。

我希望的行为有更好的实现吗?

附加信息:我使用 ThreadPoolExecutor 因为我需要 getQueue() 来检查它是否为空。我还可以在不同的实现中使用任何其他类型的 Executor Service。

提前致谢。

【问题讨论】:

  • 为什么不让执行者留在身边呢?一直重新初始化它是没有意义的。如果你觉得核心线程占用了太多资源,你可以将它们保持为零(你真的不应该强制转换为 ThreadPoolExecutor,该代码比它需要的复杂得多)。
  • 我读到只有当我关闭执行器时才会调用垃圾收集器。每个任务都会产生大量垃圾,从而导致 OOME。在不关闭 executor 服务的情况下调用 gc 是否还有另一场战争?
  • 简单的 ExecutorService 没有 getQueue() 方法,这就是我将其转换为 ThreadPoolExecutor 的原因。有没有更好的方法来初始化 ThreadPoolExecutor?或者有没有办法使用 ExecutorService 访问队列?
  • 垃圾收集器独立于任何执行器服务。如果你正确地实现了任务,一旦它们完成,它们应该被 GC 清理,因为没有其他东西应该持有引用。如果你有内存问题,你应该寻找根本原因而不是解决问题。
  • 您可以创建一个new ThreadPoolExecutor(),它允许您以多种方式对其进行配置。您关于“帮助 GC”的假设是完全错误的,执行者不会阻止任务被 GCd(除非您做的事情非常错误)。如果您只是要重新创建它,请不要关闭执行器。

标签: java executorservice


【解决方案1】:

我想关闭执行器,因为它不再需要了,所以 垃圾收集器可以完成它的工作。

但它需要的,这就是你要重新创建它的原因。无论执行器是否关闭,GC 都可以完成它的工作(除非您设法创建了一些非常特别的东西,例如 ThreadLocal 会以某种方式将对象绑定到执行器)。

我读到垃圾收集器只有在我关闭时才会被调用 执行者下线。

你要么记错了,要么你读到了错误的信息。

由于您使用单线程运行,因此您甚至不需要担心池配置。您只需要一个长寿的Executors.newFixedThreadPool(1);

如果您确实需要释放资源,可以将core pool size 配置为new ThreadPoolExecutor(0, 1, 30, TimeUnit.SECONDS, new LinkedBlockingQueue&lt;BusinessTaskRunnable&gt;());。但那是无关紧要的微优化,一个线程不应该有所作为。

【讨论】:

    猜你喜欢
    • 2017-06-09
    • 2019-12-24
    • 2023-01-11
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多