首页 文章

在ExecutorService上调用shutdown()的原因

提问于
修改于
浏览 497
61

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

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

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

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

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

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

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

4 回答

  • 35

    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() .

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

  • 5

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

    Reference Book

    Chaper:14页数:814

  • 0

    Reason for calling shutdown() on ExecutorService

    今天我遇到了一种情况,我必须等到机器准备就绪,然后再启动该机器上的一系列任务 .

    我对这台机器进行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);
    

    Second side question, a bit smaller deals with android platform.

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

  • 0

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

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

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

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

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

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

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

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

    建议的关闭方法 ExecutorService

    How to properly shutdown java ExecutorService

相关问题