繁体   English   中英

在 ExecutorService 上调用 shutdown() 的原因

[英]Reason for calling shutdown() on ExecutorService

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

关闭所做的唯一一件事(从我收集到的)就是执行正常线程完成后所做的事情。 当普通Thread执行完Runnable(或Callable)的run方法后,会传递给Garbage Collection进行回收。 使用 Executor Service 线程将被简单地搁置,它们不会被垃圾收集勾选。 为此,需要关机。

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

简单地创建ExecutorService (或根据您需要的数量而定),然后在应用程序运行期间将任务传递给他们,然后在应用程序退出或其他一些重要阶段关闭那些执行人?

我想要一些有经验的编码人员的答案,他们确实使用 ExecutorServices 编写了大量异步代码。

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

由于 CommonsWare 的评论,我使帖子中立。 我真的没有兴趣把它争论到死,而且它似乎正在领先。 我只对了解我在这里向有经验的开发人员询问的内容感兴趣,他们是否愿意分享他们的经验。 谢谢。

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 之前等待所有现有任务完成。 如果服务关闭,等待终止将阻塞 5 秒并返回 true。 这是在循环中完成的,以便您确定服务最终会关闭。 InterruptedException 每次都会被吞下。 这是关闭在整个应用程序中重复使用的执行程序服务的最佳方法。

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

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

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

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

是的。 您不应该频繁地销毁和重新创建ExecutorService 在您需要时(主要是在启动时)初始化ExecutorService并使其保持活动状态,直到您完成它。

简单地创建 ExecutorService(或根据您需要的数量而定),然后在应用程序运行期间将任务传递给他们,然后在应用程序退出或其他一些重要阶段关闭那些执行人?

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

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

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

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

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

关闭ExecutorService推荐方式:

如何正确关闭java ExecutorService

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

参考书

第14话页数:814

在 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 或处理程序或加载程序。 这是因为如果 UIThread 等待很长时间你知道会发生什么:/

尽管对于计划的任务,例如,对于 ScheduledExecutorService,这是真实的:预定分配的新案例将不会运行。

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

我没有毫不费力地抓住它的意思? 也许您需要您的应用程序无法选择向代理管理部门提交更多任务,同时您需要坐下来完成当前的 N 项任务。

除非你完全肯定你的差事最终会完成,否则你应该需要坐下来休息一段时间,然后简单地退出,抛弃正在运行的字符串。

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

另一个有趣的情况是您有一个 ScheduledExecutorService 来执行活动。

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

暂无
暂无

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

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