【发布时间】: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