简体   繁体   English

在 ExecutorService 上调用 shutdown() 的原因

[英]Reason for calling shutdown() on ExecutorService

I was reading about it quite a bit in the past couple of hours, and I simply cannot see any reason ( valid reason) to call shutdown() on the ExecutorService , unless we have a humongous application that stores, dozens and dozens of different executor services that are not used for a long time.在过去的几个小时里,我读了很多关于它的内容,我根本看不出有任何理由(正当理由)在ExecutorService上调用shutdown() ,除非我们有一个庞大的应用程序来存储数十个不同的 executor长时间不使用的服务。

The only thing (from what I gather) the shutdown does, is doing what a normal Thread does once it's done.关闭所做的唯一一件事(从我收集到的)就是执行正常线程完成后所做的事情。 When the normal Thread will finish the run method of the Runnable(or Callable), it will be passed to Garbage Collection to be collected.当普通Thread执行完Runnable(或Callable)的run方法后,会传递给Garbage Collection进行回收。 With Executor Service the threads will simply be put on hold, they will not be ticked for the garbage collection.使用 Executor Service 线程将被简单地搁置,它们不会被垃圾收集勾选。 For that, the shutdown is needed.为此,需要关机。

Ok back to my question.好的回到我的问题。 Is there any reason to call shutdown on ExecutorService very often, or even right after submitting to it some tasks?是否有任何理由经常在ExecutorService上调用关闭,甚至在向其提交某些任务后立即调用? I would like to leave behind the case someone is doing it and right after that calls to awaitTermination() as this is validated.我想留下有人正在做的情况,然后在调用awaitTermination()之后awaitTermination()进行验证。 Once we do that, we have to recreate a new ExecutorService all over again, to do the same thing.一旦我们这样做了,我们必须重新创建一个新的ExecutorService来做同样的事情。 Isn't the whole idea for the ExecutorService to reuse the threads? ExecutorService重用线程的全部想法不是吗? So why destroy the ExecutorService so soon?那么为什么要这么快销毁ExecutorService呢?

Isn't it a rational way to simply create ExecutorService (or couple depending on how many you need), then during the application running pass to them the tasks once they come along, and then on the application exit or some other important stages shutdown those executors?简单地创建ExecutorService (或根据您需要的数量而定),然后在应用程序运行期间将任务传递给他们,然后在应用程序退出或其他一些重要阶段关闭那些执行人?

I'd like an answer from some experienced coders who do write a lot of asynchronous code using the ExecutorServices.我想要一些有经验的编码人员的答案,他们确实使用 ExecutorServices 编写了大量异步代码。

Second side question, a bit smaller deals with the android platform.第二个方面的问题,与 android 平台的交易有点小。 IF some of you will say that it's not the best idea to shutdown executors every time, and your program on android, could you tell me how do you handle those shutdowns (to be specific - when you execute them) when we deal with different events of the application life cycle.如果你们中的一些人会说每次关闭执行程序并不是最好的主意,以及你在 android 上的程序,你能告诉我当我们处理不同的事件时你如何处理这些关闭(具体来说 - 当你执行它们时)应用程序生命周期。

Because of the CommonsWare comment, I made the post neutral.由于 CommonsWare 的评论,我使帖子中立。 I really am not interested in arguing about it to death and it seems it's leading there.我真的没有兴趣把它争论到死,而且它似乎正在领先。 I'm only interested in learning about what I asked here from experienced developers if they are willing to share their experiences.我只对了解我在这里向有经验的开发人员询问的内容感兴趣,他们是否愿意分享他们的经验。 Thanks.谢谢。

The shutdown() method does one thing: prevents clients to send more work to the executor service. shutdown()方法做一件事:阻止客户端向执行程序服务发送更多工作。 This means all the existing tasks will still run to completion unless other actions are taken.这意味着除非采取其他操作,否则所有现有任务仍将运行完成。 This is true even for scheduled tasks, eg, for a ScheduledExecutorService: new instances of the scheduled task won't run.即使对于计划任务也是如此,例如,对于 ScheduledExecutorService:计划任务的新实例不会运行。 It also frees up any background thread resources.它还释放任何后台线程资源。 This can be useful in various scenarios.这在各种情况下都很有用。

Let's assume you have a console application which has an executor service running N tasks.假设您有一个控制台应用程序,它有一个运行 N 个任务的执行程序服务。 If the user hits CTRL-C, you expect the application to terminate, possibly gracefully.如果用户按下 CTRL-C,您希望应用程序终止,可能会正常终止。 What does it mean gracefully?优雅地是什么意思? Maybe you want your application to not be able to submit more tasks to the executor service and at the same time you want to wait for your existing N tasks to complete.也许您希望您的应用程序无法向执行程序服务提交更多任务,同时您希望等待您现有的 N 个任务完成。 You could achieve this using a shutdown hook as a last resort:您可以使用关闭挂钩作为最后的手段来实现这一点:

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

This hook will shutdown the service, which will prevent your application to submit new tasks, and wait for all the existing tasks to complete before shutting down the JVM.这个钩子将关闭服务,这将阻止您的应用程序提交新任务,并在关闭 JVM 之前等待所有现有任务完成。 The await termination will block for 5 seconds and return true if the service is shutdown.如果服务关闭,等待终止将阻塞 5 秒并返回 true。 This is done in a loop so that you're sure the service will shutdown eventually.这是在循环中完成的,以便您确定服务最终会关闭。 The InterruptedException gets swallowed each time. InterruptedException 每次都会被吞下。 This is the best way to shutdown an executor service that gets reused all over your application.这是关闭在整个应用程序中重复使用的执行程序服务的最佳方法。

This code isn't perfect.这段代码并不完美。 Unless you're absolutely positive your tasks will eventually terminate, you might want to wait for a given timeout and then just exit, abandoning the running threads.除非您绝对肯定您的任务最终会终止,否则您可能希望等待给定的超时时间,然后退出,放弃正在运行的线程。 In this case it would make sense to also call shutdownNow() after the timeout in a final attempt to interrupt the running threads ( shutdownNow() will also give you a list of tasks waiting to run).在这种情况下,在最后一次尝试中断正在运行的线程时在超时后调用shutdownNow()也是有意义的( shutdownNow()还会为您提供等待运行的任务列表)。 If your tasks are designed to respond to interruption this will work fine.如果您的任务旨在响应中断,这将正常工作。

Another interesting scenario is when you have a ScheduledExecutorService that performs a periodic task.另一个有趣的场景是当您有一个执行周期性任务的 ScheduledExecutorService 时。 The only way to stop the chain of periodic tasks is to call shutdown() .停止周期性任务链的唯一方法是调用shutdown()

EDIT: I'd like to add that I wouldn't recommend using a shutdown hook as shown above in the general case: it can be error-prone and should be a last resort only.编辑:我想补充一点,我不建议在一般情况下使用如上所示的关闭钩子:它可能容易出错,并且应该只是最后的手段。 Moreover, if you have many shutdown hooks registered, the order in which they will run is undefined, which might be undesirable.此外,如果您注册了许多关闭挂钩,则它们运行的​​顺序是未定义的,这可能是不可取的。 I'd rather have the application explicitly call shutdown() on InterruptedException .我宁愿让应用程序在InterruptedException上显式调用shutdown()

Isn't the whole idea for the ExecutorService to reuse the threads? ExecutorService 重用线程的全部想法不是吗? So why destroy the ExecutorService so soon?那么为什么要这么快销毁 ExecutorService 呢?

Yes.是的。 You should not destroy and re-create ExecutorService frequently.您不应该频繁地销毁和重新创建ExecutorService Initialize ExecutorService when you require (mostly on start-up) and keep it active until you are done with it.在您需要时(主要是在启动时)初始化ExecutorService并使其保持活动状态,直到您完成它。

Isn't it a rational way to simply create ExecutorService (or couple depending on how many you need), then during the application running pass to them the tasks once they come along, and then on the application exit or some other important stages shutdown those executors?简单地创建 ExecutorService(或根据您需要的数量而定),然后在应用程序运行期间将任务传递给他们,然后在应用程序退出或其他一些重要阶段关闭那些执行人?

Yes.是的。 It's rational to shutdown ExecutorService on important stages like application exit etc.在应用程序退出等重要阶段关闭ExecutorService是合理的。

Second side question, a bit smaller deals with android platform.第二个方面的问题,与 android 平台的交易有点小。 IF some of you will say that it's not best idea to shutdown executors every time, and you program on android, could you tell me how you handle those shutdowns (to be specific, when you execute them) when we deal with different events of application life cycle.如果你们中的一些人会说每次关闭执行程序并不是最好的主意,并且你在 android 上编程,你能告诉我当我们处理应用程序的不同事件时你如何处理这些关闭(具体来说,当你执行它们时)生命周期。

Assume that ExecutorService is shared across different Activities in your application.假设ExecutorService在您的应用程序中的不同活动之间共享。 Each activity will be paused/resumed at different intervals of time and still you need one ExecutorService per your application.每个活动将在不同的时间间隔暂停/恢复,但每个应用程序仍然需要一个ExecutorService

Instead of managing the state of ExecutorService in Activity life cycle methods, move ExecutorService management ( Creation/Shutdown) to your custom Service .不是在 Activity 生命周期方法中管理ExecutorService的状态,而是将 ExecutorService 管理(创建/关闭)移动到您的自定义Service

Create ExecutorService in Service => onCreate() and shutdown it properly in onDestroy()在 Service => onCreate()创建ExecutorService并在onDestroy()正确关闭它

Recommended way of shutting down ExecutorService :关闭ExecutorService推荐方式:

How to properly shutdown java ExecutorService 如何正确关闭java ExecutorService

An ExecutorService should be shut down once it is no longer needed to free up system resources and to allow graceful application shutdown.一旦不再需要 ExecutorService 以释放系统资源并允许正常关闭应用程序,就应该关闭它。 Because the threads in an ExecutorService may be nondaemon threads, they may prevent normal application termination.因为 ExecutorService 中的线程可能是非守护线程,它们可能会阻止正常的应用程序终止。 In other words, your application stays running after completing its main method.换句话说,您的应用程序在完成其 main 方法后保持运行。

Reference Book参考书

Chaper:14 Page:814第14话页数:814

Reason for calling shutdown() on ExecutorService在 ExecutorService 上调用 shutdown() 的原因

Today I encountered a situation where I have to wait until a machine is ready, before starting a series of tasks on that machine.今天我遇到了一种情况,我必须等到一台机器准备就绪,然后才能在该机器上启动一系列任务。

I make a REST call to this machine, if I don't receive 503 (Server Unavailable) then the machine is ready to process my requests.我对这台机器进行 REST 调用,如果我没有收到 503(服务器不可用),那么该机器已准备好处理我的请求。 So, I wait until I get 200 (Success) for the first REST call.所以,我等到第一个 REST 调用得到 200(成功)。

There are multiple ways to achieve it, I used ExecutorService to create a thread and scheduled it to run after every X Seconds.有多种方法可以实现它,我使用 ExecutorService 创建一个线程并安排它在每 X 秒后运行一次。 So, I need to stop this thread on a condition, check this out...所以,我需要在某个条件下停止这个线程,看看这个......

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

Second side question, a bit smaller deals with android platform.第二个方面的问题,与 android 平台的交易有点小。

Maybe I can answer if you'll provide bit more context!如果您提供更多背景信息,也许我可以回答! Also from my experience with Android development it's rarely you need Threads.此外,根据我在 Android 开发方面的经验,您很少需要 Threads。 Are you developing a Game or an app which needs threads for performance?您是否正在开发需要线程以提高性能的游戏或应用程序? If not, in Android you have other ways to tackle problems like the scenario that I explained above.如果没有,在 Android 中,您有其他方法来解决问题,例如我上面解释的场景。 You can rather use TimerTask, AsyncTask or Handlers or Loaders based on context.您可以根据上下文使用 TimerTask、AsyncTask 或处理程序或加载程序。 This is because if UIThread waits for long you know what happens :/这是因为如果 UIThread 等待很长时间你知道会发生什么:/

This is genuine notwithstanding for planned undertakings, eg, for a ScheduledExecutorService: new cases of the booked assignment won't run.尽管对于计划的任务,例如,对于 ScheduledExecutorService,这是真实的:预定分配的新案例将不会运行。

We should expect you have a comfort application which has an agent administration running N errands.我们应该期望你有一个舒适的应用程序,它有一个运行 N 个差事的代理管理。

I'm not catching it's meaning effortlessly?我没有毫不费力地抓住它的意思? Perhaps you need your application to not have the option to submit more assignments to the agent administration and in the meantime you need to sit tight for your current N undertakings to finish.也许您需要您的应用程序无法选择向代理管理部门提交更多任务,同时您需要坐下来完成当前的 N 项任务。

Except if you're totally positive your errands will in the end, you should need to sit tight for a given break and after that simply exit, deserting the running strings.除非你完全肯定你的差事最终会完成,否则你应该需要坐下来休息一段时间,然后简单地退出,抛弃正在运行的字符串。

In the event that your activitys are intended to react to interference this will work fine.如果您的活动旨在对干扰做出反应,这将正常工作。

Another intriguing situation is the point at which you have a ScheduledExecutorService that plays out an activity.另一个有趣的情况是您有一个 ScheduledExecutorService 来执行活动。

The best way to stop the chain of activity is to call shutdown()停止活动链的最好方法是调用 shutdown()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM