在ExecutorService上调用shutdown()的原因

Luc*_*cas 71 java android executorservice

在过去的几个小时里,我正在阅读相当多shutdown()的内容ExecutorService,除非我们有一个庞大的应用程序存储,几十个和几十个不使用的不同的执行程序服务,我根本看不出有任何理由(有正当理由).很长时间.

关闭所做的唯一事情(从我收集的内容)是正常线程完成后所做的事情.当普通的Thread完成Runnable(或Callable)的run方法时,它将被传递给Garbage Collection进行收集.使用Executor Service,线程将被暂停,不会为垃圾收集打勾.为此,需要关机.

好的,回到我的问题.是否有任何理由ExecutorService经常或甚至在提交一些任务后立即调用关机?我想留下有人正在做的情况,并在调用之后,awaitTermination()因为这是有效的.一旦我们这样做,我们必须重新创建一个新的ExecutorService,做同样的事情.是不是ExecutorService重用线程的整个想法?那么为什么要ExecutorService这么快就毁灭呢?

简单地创建ExecutorService(或依赖于你需要的数量)是不是一种合理的方式,然后在应用程序运行期间,一旦它们出现就将任务传递给它们,然后在应用程序出口或其他一些重要阶段关闭那些执行程序?

我想从一些经验丰富的编码员那里回答,他们使用ExecutorServices写了很多异步代码.

第二个问题,与平台有点小的交易.如果你们中的一些人会说每次关闭执行程序并不是最好的想法,并且你在android上编程,你能不能告诉我当你处理不同的事件时你如何处理这些关闭(具体来说 - 当你执行它们时)应用生命周期.

由于CommonsWare的评论我发布了中立的帖子.我真的没有兴趣争论死亡,似乎它在那里领先.如果他们愿意分享他们的经验,我只对从经验丰富的开发者那里了解我的问题感兴趣.谢谢.

Gio*_*tta 49

shutdown()方法做了一件事:阻止客户端向执行程序服务发送更多工作.这意味着除非采取其他操作,否则所有现有任务仍将完成.即使对于计划任务也是如此,例如,对于ScheduledExecutorService:计划任务的新实例将不会运行.这在各种场景中都很有用.

假设您有一个控制台应用程序,它具有运行N个任务的执行程序服务.如果用户点击CTRL-C,您希望应用程序可能正常终止.它优雅地意味着什么?也许您希望您的应用程序无法向执行程序服务提交更多任务,同时您希望等待现有的N个任务完成.您可以使用关闭挂钩作为最后的手段来实现此目的:

final ExecutorService service = ... // get it somewhere

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Performing some shutdown cleanup...");
        service.shutdown();
        while (true) {
            try {
                System.out.println("Waiting for the service to terminate...");
                if (service.awaitTermination(5, TimeUnit.SECONDS)) {
                    break;
                }
            } catch (InterruptedException e) {
            }
        }
        System.out.println("Done cleaning");
    }
}));
Run Code Online (Sandbox Code Playgroud)

此挂钩将关闭该服务,这将阻止您的应用程序提交新任务,并在关闭JVM之前等待所有现有任务完成.await终止将阻塞5秒,如果服务关闭则返回true.这是在循环中完成的,这样您就可以确定服务最终会关闭.每次都会吞下InterruptedException.这是关闭在应用程序中重用的执行程序服务的最佳方法.

这段代码并不完美.除非你绝对肯定你的任务最终会终止,你可能想要等待给定的超时,然后退出,放弃正在运行的线程.在这种情况下,shutdownNow()在最后一次尝试中断正在运行的线程的超时后调用也是有意义的(shutdownNow()还会给你一个等待运行的任务列表).如果您的任务旨在响应中断,这将正常工作.

另一个有趣的场景是,您有一个执行定期任务的ScheduledExecutorService.停止周期性任务链的唯一方法是调用shutdown().

编辑:我想补充一点,我不建议在一般情况下使用如上所示的关闭钩子:它可能容易出错,应该只是最后的手段.此外,如果您注册了许多关闭挂钩,它们将运行的顺序是未定义的,这可能是不合需要的.我宁愿让应用程序显式调用shutdown()InterruptedException.

  • 我知道了.我建议你使用[缓存线程池](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool()),永远不要调用`shutdown() `在它上面,这样你就不会在不必要的时候浪费资源.如果应用程序确实关闭,则池中的线程最终将被垃圾收集(默认情况下它们空闲60秒后).请注意,如果您希望池有界或者想要不同的线程生命周期,则可以直接创建`ThreadPoolExecutor`. (3认同)
  • 没有理由一直调用shutdown().事实上,这可能是绝对错误的事情,因为它会阻止您再次重用执行程序服务.在服务生命周期结束时调用它的原因是,当你注意到时,线程最终可以被垃圾收集.如果不这样做,那些线程将使JVM保持活动状态,即使它们处于空闲状态. (2认同)
  • 我没有Android经验,但是我想您应该在应用程序关闭时将其关闭,以允许JVM最终退出。 (2认同)

Rav*_*abu 9

ExecutorService不是重用线程的全部想法吗?那么为什么要这么快就销毁ExecutorService呢?

是.你不应该ExecutorService经常破坏和重新创建.ExecutorService在您需要时进行初始化(主要是在启动时)并保持活动状态,直到您完成它为止.

简单地创建ExecutorService(或者根据你需要的数量来配置)是不是一种合理的方式,然后在应用程序运行期间,一旦它们出现就将任务传递给它们,然后在应用程序出口或其他一些重要阶段关闭那些遗嘱执行人?

是.ExecutorService在应用程序退出等重要阶段关闭是合理的.

第二个问题,与平台有点小的交易.如果你们中的一些人会说每次关闭执行程序并不是最好的想法,并且你在android上编程,你能告诉我你在处理不同的应用程序事件时如何处理这些关闭(具体来说,当你执行它们时)生命周期.

假设ExecutorService在应用程序中的不同活动之间共享.每个活动将以不同的时间间隔暂停/恢复,并且您的ExecutorService每个应用程序仍需要一个活动.

而不是管理ExecutorServiceActivity生命周期方法的状态,将ExecutorService管理(创建/关闭)移动到您的自定义服务.

ExecutorService在服务中创建=> onCreate()并正确关闭它onDestroy()

推荐的关闭方式ExecutorService:

如何正确关闭java ExecutorService


emo*_*mon 5

一旦不再需要释放系统资源并允许正常关闭应用程序,就应该关闭 ExecutorService。因为 ExecutorService 中的线程可能是非守护线程,它们可能会阻止正常的应用程序终止。换句话说,您的应用程序在完成其 main 方法后保持运行。

参考书

第14章 第814页