在ExecutorService上调用shutdown()的原因

问题描述 投票:66回答:5

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

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

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

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

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

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

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

java android executorservice
5个回答
44
投票

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


7
投票

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

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

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

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

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

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

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

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

关闭ExecutorService的推荐方法:

How to properly shutdown java ExecutorService


3
投票

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

Reference Book

第14章:814


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开发方面的经验,你很少需要Threads。您是在开发一款需要线程性能的游戏还是应用程序?如果没有,在Android中你有其他方法来解决我上面解释过的问题。您可以根据上下文使用TimerTask,AsyncTask或Handlers或Loaders。这是因为如果UIThread等待很长时间你会知道会发生什么:/


0
投票

尽管有计划的承诺,例如对于ScheduledExecutorService,这是真实的:预订分配的新案例将不会运行。

我们应该期待你有一个舒适的应用程序,它有一个运行N个差事的代理管理。

我没有毫不费力地抓住它的含义?也许您需要您的申请无法向代理商管理部门提交更多的任务,同时您需要紧张地完成当前的N项任务。

除非你完全肯定你的差事,最后你需要坐下来休息一段时间,然后退出,离开跑道。

如果您的活动旨在对干扰做出反应,这将很好。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.