在ExecutorService上调用shutdown()的原因

时间:2013-04-20 17:09:14

标签: java android executorservice

在过去的几个小时里,我正在阅读相当多的内容,我在shutdown()上看不到任何理由(有效原因)来致电ExecutorService,除非我们有一个庞大的应用程序,存储,数十个和许多不同的执行器服务长期不使用。

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

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

简单地创建ExecutorService(或根据您需要的数量而不是一对)是不是一种理性的方式,然后在应用程序运行期间,一旦它们出现就传递给它们,然后在应用程序出口处还是其他一些重要阶段会关闭那些遗嘱执行人?

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

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

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

5 个答案:

答案 0 :(得分:41)

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");
    }
}));

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

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

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

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

答案 1 :(得分:6)

  

对于ExecutorService重用线程的整个想法是不是?那么为什么要这么快就销毁ExecutorService呢?

是。您不应经常销毁和重新创建ExecutorService。在您需要时(主要是在启动时)初始化ExecutorService并保持活动状态,直到您完成它为止。

  

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

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

  

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

假设您的应用程序中的不同活动共享ExecutorService。每个活动将在不同的时间间隔暂停/恢复,但您的申请仍然需要一个ExecutorService

不要在Activity生命周期方法中管理ExecutorService的状态,而是将ExecutorService管理(创建/关闭)移动到您的自定义Service

在Service =>中创建ExecutorService onCreate()并在onDestroy()

中正确关闭它

关闭ExecutorService的建议方式:

How to properly shutdown java ExecutorService

答案 2 :(得分:3)

  

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

Reference Book

章中:14 页:814

答案 3 :(得分:0)

在ExecutorService上调用shutdown()的原因

今天我遇到了一种情况,我必须等到机器准备就绪,然后才开始在那台机器上完成一系列任务。

我对这台机器进行REST调用,如果我没有收到503(服务器不可用),那么机器已准备好处理我的请求。所以,我等到第一次REST呼叫得到200(成功)。

有多种方法可以实现它,我使用ExecutorService创建一个线程并安排它在每X秒后运行。所以,我需要在一个条件下停止这个线程,检查一下......

final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable task = () -> {
        try {
            int statusCode = restHelper.firstRESTCall();

            if (statusCode == 200) {
                executor.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    };

    int retryAfter = 60;
    executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);

第二个问题,与Android平台相比有点小。

如果你能提供更多的背景,也许我可以回答! 另外根据我在Android开发方面的经验,你很少需要Threads。您是在开发一款需要线程性能的游戏还是应用程序?如果没有,在Android中你有其他方法来解决我上面解释过的问题。您可以根据上下文使用TimerTask,AsyncTask或Handlers或Loaders。这是因为如果UIThread等待很长时间你会知道会发生什么:/

答案 4 :(得分:0)

尽管有计划的工作,例如ScheduledExecutorService,这还是真实的:预定任务的新案例将不会运行。

我们应该期望您拥有一个舒适的应用程序,该应用程序具有运行N ergents的代理管理。

我没有轻易理解它的意思吗?也许您需要您的应用程序不具有向代理人管理提交更多任务的选项,同时您需要坐下来完成当前的N个任务。

除非您对自己的差事最终抱有完全的肯定,否则您应该为给定的休息时间坐好,然后简单地退出,放弃奔跑的绳子。

如果您的活动旨在对干扰做出反应,则可以正常工作。

另一种有趣的情况是您拥有一个ScheduledExecutorService来播放活动。

停止活动链的最佳方法是调用shutdown()