111

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.

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. With Executor Service the threads will simply be put on hold, they will not be ticked for the garbage collection. 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? I would like to leave behind the case someone is doing it and right after that calls to awaitTermination() as this is validated. Once we do that, we have to recreate a new ExecutorService all over again, to do the same thing. Isn't the whole idea for the ExecutorService to reuse the threads? So why destroy the ExecutorService so soon?

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?

I'd like an answer from some experienced coders who do write a lot of asynchronous code using the ExecutorServices.

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

Because of the CommonsWare comment, I made the post neutral. 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.

Andrzej Sydor
  • 1,373
  • 4
  • 13
  • 28
Lucas
  • 3,521
  • 3
  • 27
  • 39
  • 4
    "I see many times sample codes, in which all the time, there is a shutdown() invocation right after submiting or executing tasks" -- feel free to use hyperlinks to provide evidence of your claims. Personally, I have never seen any "sample codes" that do what you state. It is possible that you are misinterpreting something, and we can only point that out to you if we know what "sample codes" you are examining. – CommonsWare Apr 20 '13 at 17:49
  • 9
    Hi CommonsWare. First of all, I see an aggresive tone of yours(or so that seems) towards me, which I think is not validated here. I was not trying to portrait people in negative way. As for your quote, I was mostly talking about the Thinking In Java IV edition, Multitasking part. You can find many instances of that in Bruce Eckel's examples. They are mostly simple, but never the less the impression Bruce put on me, was to use shutdown very often. In any way, you focused on something that was not the main part of my post. I removed those parts cause I really don't wish to argue about it. – Lucas Apr 20 '13 at 20:13
  • 2
    hay @CommonsWare in Thinking in java book by Bruce Eckel..in concurrency/Executor page 804 Fourth Edition , he always use shutdown() method right after submitting or executing tasks in simple apps to illustrate how Executor works as Lucas said – Error Nov 12 '15 at 09:36
  • 2
    I know this is an old post, but I think the OP's question still stands and is valid. I've also come across many sample codes where "there is a shutdown() invocation right after execute()". http://tutorials.jenkov.com/java-util-concurrent/executorservice.html (first tutorial that comes up when you google "java executorservice example") – baekacaek Dec 10 '15 at 20:52
  • Thank you, I had the same question that raised with these "sample codes". http://www.journaldev.com/2340/java-scheduler-scheduledexecutorservice-scheduledthreadpoolexecutor-example – Gregordy Oct 17 '16 at 16:58
  • My app would not terminate until I called `shutdown()` on the executor service returned by `Executors.newSingleThreadScheduledExecutor()`. – Joe Lapp May 09 '18 at 05:19

6 Answers6

68

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.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
Giovanni Botta
  • 9,626
  • 5
  • 51
  • 94
  • 1
    Sorry Giovanni for late response, and thank you for that btw. Yes, I'm aware of how Executor works, which I tried to explain in my question. The shutdown does what you said, and also it allows garbage collector to collect those dead threads, and in effect to collect ExecutorService instance. My question was specific. Is there any reason to call "shutdown()" all the time, right after you submit/execute anything on ExecutorService. The second part of the question is strictly in relation to Android architecture. If the answer to previous is no, then when to call shutdown during and. lifecycle. – Lucas Dec 01 '13 at 10:40
  • 5
    There's no reason to call shutdown() all the time. In fact, that might be the absolute wrong thing to do since it will prevent you from reusing the executor service again. The reason to call it at the end of the life cycle of the service is so that the threads can be finally garbage collected as you noticed. If you don't, those threads will keep the JVM alive even though they are idle. – Giovanni Botta Dec 02 '13 at 14:44
  • "There's no reason to call shutdown() all the time. In fact, that might be the absolute wrong thing to do since it will prevent you from reusing the executor service again". That's exactly my reasoning, and my dillema from the original question. So to reiterate, the question is: When should I shutdown my ExecutiveService in the Android lifecycle? – Lucas Dec 02 '13 at 19:12
  • 2
    I have no Android experience, but I would guess you should shut it down when your application shuts down, in order to allow the JVM to finally exit. – Giovanni Botta Dec 02 '13 at 20:26
  • By the way, that is true if you use your executor service throughout the application life cycle. If you only use it rarely, it might make sense to shut it down right after you're done and then create a new one when you need it. – Giovanni Botta Dec 02 '13 at 20:34
  • Unfortunetly Giovani, android lifecycle does not include explicit app termination, so you never know (you can do a hack arounds, but that's a no-no) when the application is indeed done, or not. And since youy're also not an android developer, I will not drag you into the way I'm thinking about it, since you don't have enough knoledge about the platform. Thanks for taking the time though with your responses. – Lucas Dec 03 '13 at 07:42
  • 3
    I see. I suggest you use a [cached thread pool](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool()) and never call `shutdown()` on it so that you don't waste resources when unnecessary. If the application does shut down, the threads in the pool will eventually be garbage collected (after they are idle for 60 seconds by default). Note that if you want the pool to be bounded or want a different thread life time you can create a `ThreadPoolExecutor` directly. – Giovanni Botta Dec 03 '13 at 15:48
15

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

Ravindra babu
  • 37,698
  • 11
  • 250
  • 211
  • I think this lifeCycle dependency issue is relative, since if something is still sending you runnable commands, AND If your executor was .shutdown() by a lifeCycle termination, the entire class would still be in the need to be dereferenced from the producer sending the commands (as it leaks if don't). This means that: IF the entire LifeCycle system is correctly done, AND every Consumer is properly dereferenced from its Producer, every .shutdown() would be redundant since the entire enclosure of the executor would still be eligible for garbage collection anyways. – Delark Aug 11 '21 at 16:48
  • Now this changes entirely if the phases chosen are onStart() for creation + onStop() for shutdown(); – Delark Aug 11 '21 at 16:49
  • 1
    “You should not destroy and re-create ExecutorService frequently.” While true today (at Java 17), I want to note that such advice will *not* apply to [virtual thread](https://openjdk.java.net/jeps/8277131)-backed executor services coming to Java if [*Project Loom*](https://wiki.openjdk.java.net/display/loom/Main) succeeds. Under Loom, we will frequently launch and close virtual-thread executor services at the drop of a hat. There may be other reasons to constrain our use of background virtual threads, but being conservative with backing thread pools will no longer be one of those reasons. – Basil Bourque Feb 03 '22 at 20:03
7

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

emon
  • 1,629
  • 1
  • 17
  • 18
1

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 :/

0

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

Devlax
  • 3
  • 5
0

I recently found in my code that if I'm not using shutdown() after finishing some parallel work, the threads are not closed automatically, even if the parallel work was completed. This created many unused threads that eventually crashed the code due to out-of-memory problems.

Mr.O
  • 342
  • 2
  • 19