在 ExecutorService 上调用 close()的原因

在过去的几个小时里,我读了很多关于它的文章,除非我们有一个巨大的应用程序,它存储了很多很多不同的执行服务,但是很长一段时间都没有使用,否则我就找不到任何理由(有效的理由)在 ExecutorService上调用 shutdown()

关闭所做的唯一一件事(据我所知)就是完成普通 Thread 完成后所做的事情。当普通线程完成 Runnable (或 Callable)的 run 方法时,它将被传递给要收集的垃圾收集。使用 ExecuterService,线程将被简单地暂停,不会为垃圾回收勾选线程。为此,政府必须停摆。

好吧,回到我的问题。是否有任何理由经常在 ExecutorService上调用关机,甚至在提交了一些任务之后立即调用关机?我想留下的情况下,有人正在这样做,然后立即调用 awaitTermination(),因为这是有效的。一旦我们做到这一点,我们必须重新创建一个新的 ExecutorService所有再次,做同样的事情。ExecutorService重用线程的整个想法不就是这样吗?那为什么这么快就摧毁了 ExecutorService

这难道不是一种简单的创建 ExecutorService(或者根据需要创建多少对 ExecutorService)的合理方式吗? 然后在应用程序运行期间,一旦任务出现,就将它们传递给它们,然后在应用程序退出或者其他一些重要阶段关闭这些执行器?

我想从一些有经验的程序员那里得到一个答案,他们使用 ExecutorServices 编写了很多异步代码。

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

因为共享软件的评论,我把文章写成了中立的。我真的没有兴趣为此争论到死,而且它似乎正在引向那里。如果有经验的开发人员愿意分享他们的经验,我只对我在这里向他们询问的内容感兴趣。谢谢。

96817 次浏览

The shutdown() method does one thing: prevents clients to send more work to the executor service. This means all the existing tasks will still run to completion unless other actions are taken. This is true even for scheduled tasks, e.g., for a ScheduledExecutorService: new instances of the scheduled task won't run. 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. If the user hits CTRL-C, you expect the application to terminate, possibly gracefully. 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. 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. The await termination will block for 5 seconds and return true if the service is shutdown. This is done in a loop so that you're sure the service will shutdown eventually. The InterruptedException gets swallowed each time. 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). 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. The only way to stop the chain of periodic tasks is to call 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.

Isn't the whole idea for the ExecutorService to reuse the threads? So why destroy the ExecutorService so soon?

Yes. You should not destroy and re-create ExecutorService frequently. Initialize ExecutorService when you require (mostly on start-up) and keep it active until you are done with it.

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?

Yes. It's rational to shutdown ExecutorService on important stages like application exit etc.

Second side question, a bit smaller deals with android platform. 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.

Assume that ExecutorService is shared across different Activities in your application. Each activity will be paused/resumed at different intervals of time and still you need one ExecutorService per your application.

Instead of managing the state of ExecutorService in Activity life cycle methods, move ExecutorService management ( Creation/Shutdown) to your custom Service.

Create ExecutorService in Service => onCreate() and shutdown it properly in onDestroy()

Recommended way of shutting down ExecutorService :

How to properly shutdown java ExecutorService

Reason for calling shutdown() on ExecutorService

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. So, I wait until I get 200 (Success) for the first REST call.

There are multiple ways to achieve it, I used ExecutorService to create a thread and scheduled it to run after every X Seconds. 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.

Maybe I can answer if you'll provide bit more context! Also from my experience with Android development it's rarely you need 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. You can rather use TimerTask, AsyncTask or Handlers or Loaders based on context. This is because if UIThread waits for long you know what happens :/

An ExecutorService should be shut down once it is no longer needed to free up system resources and to allow graceful application shutdown. Because the threads in an ExecutorService may be nondaemon threads, they may prevent normal application termination. In other words, your application stays running after completing its main method.

Reference Book

Chaper:14 Page:814

This is genuine notwithstanding for planned undertakings, e.g., for a ScheduledExecutorService: new cases of the booked assignment won't run.

We should expect you have a comfort application which has an agent administration running N errands.

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.

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.

The best way to stop the chain of activity is to call shutdown()