36

I put a bunch of runnable objects into an ExecutorService:

// simplified content of main method
ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i = 0; i < workerCount; i++) {
    threadPool.execute(new Worker());
}

I would expect my program/process to stop immediately after all workers are done. But according to my log, it takes another 20-30 seconds until that happens. The workers do not allocate any resources, in fact, they do nothing at the moment.

Don't get me wrong, this is not a crucial problem for me, I'm just trying to understand what is happening and I'm wondering if this is normal behavior.

alapeno
  • 2,724
  • 6
  • 36
  • 53

6 Answers6

42

Executors.newCachedThreadPool() uses Executors.defaultThreadFactory() for its ThreadFactory. defaultThreadFactory's javadocs say that "each new thread is created as a non-daemon thread" (emphasis added). So, the threads created for the newCachedThreadPool are non-daemon. That means that they'll prevent the JVM from exiting naturally (by "naturally" I mean that you can still call System.exit(1) or kill the program to cause the JVM to halt).

The reason the app finishes at all is that each thread created within the newCachedThreadPool times out and closes itself after some time of inactivity. When the last one of them closes itself, if your application doesn't have any non-daemon threads left, it'll quit.

You can (and should) close the ExecutorService down manually via shutdown or shutdownNow.

See also the JavaDoc for Thread, which talks about daemon-ness.

yshavit
  • 42,327
  • 7
  • 87
  • 124
  • Although this will work, the right answer is that you _must_ shutdown the `ExecutorService` @alapeno. – Gray Nov 18 '13 at 21:31
  • @Gray: No, look in the Javadoc I quoted in my answer - those threads shut down automatically if they are idle for 60 seconds. – Russell Zahniser Nov 18 '13 at 21:41
  • @Gray: If by "core thread" you mean the main thread, it terminates at the end of `main()`. If you mean the AWT thread, it terminates when there are no longer any displayable components. And there is no background thread "running" the `ExecutorService` beyond the threads in its pool; enqueuing a task in `execute()` (for example) is done right in that method in the thread that called it. – Russell Zahniser Nov 19 '13 at 13:58
  • The cached threads above the core-threads in the thread-pool (see `ThreadPoolExecutor`) are shutdown automatically @RussellZahniser but the core-threads in the pool never shutdown by themselves unless they are daemon threads. If any tasks have been submitted then you have to wait for the cached threads to timeout and be reaped. – Gray Nov 19 '13 at 14:15
  • @Gray: I think you missed the fact that OP is using `Executors.newCachedThreadPool()`, which has a core size of 0. – Russell Zahniser Nov 19 '13 at 15:51
  • No, I understand that @RussellZahniser. I always try to answer for posterity. – Gray Nov 19 '13 at 15:53
  • Keep in mind that `ThreadPoolExecutor` has a `finalize()` method that calls `shutdown()`, which interrupts idle threads. So if you don't care about 1. how long it takes the currently running tasks to complete or 2. waiting for queued but non-running tasks to complete, you don't absolutely need to shut it down manually though it is a good habit. – Shannon Jan 15 '16 at 19:57
8

I would expect my program/process to stop immediately after all workers are done. But according to my log, it takes another 20-30 seconds until that happens. The workers do not allocate any resources, in fact, they do nothing at the moment.

The problem is that you are not shutting down your ExecutorService. After you submit all of the jobs to the service, you should shutdown the service or the JVM will not terminate unless all of the threads in it are daemon threads. If you do not shutdown the thread-pool then any threads associated with the ExecutorService, again if not daemon, will stop the JVM from finishing. If you've submitted any tasks to a cached thread pool then you will have to wait for the threads to timeout and get reaped before the JVM will finish.

ExecutorService threadPool = Executors.newCachedThreadPool();
for(int i = 0; i < workerCount; i++) {
    threadPool.execute(new Worker());
}
// you _must_ do this after submitting all of your workers
threadPool.shutdown();

Starting the threads as daemon is most likely not what you want to do because your application may stop before the tasks have completed and all of the tasks will be terminated immediately at that time. I just did a quick audit and of the 178 times we use ExecutorService classes in our production code, only 2 of them were started as daemon threads. The rest are properly shutdown.

If you need to force an ExecutorService to stop when the application is exiting then using shutdownNow() with proper handling of the thread interrupt flags is in order.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • 2
    What is your definition of "must"? The javadocs for ExecutorService don't say it "must" be shut down (just that it "can" be), and your assertion that it will hang (not "may" hang) is either a restatement of the OP's question, or just incorrect, depending on how you define "hang." I agree that it's good practice to shut down the `ExecutorService`, but if you're going to downvote _and_ make this assertion three times on this question, frankly I think you need to back it up. – yshavit Nov 19 '13 at 04:49
  • I've modified my answer @yshavit to add more details. Although the javadocs do say that it "can", if you _don't_ shut it down then the JVM won't terminate. I've write 100s of `ExecutorService` implementations and I've rarely set them up as non-daemon threads. Shutting them down at the end is the right pattern. – Gray Nov 19 '13 at 13:46
  • Fair enough, and it's anyway enough of a best practice to be almost a must. – yshavit Nov 19 '13 at 14:36
5

Basically on an ExecutorService you call shutdown() and then awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
   taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}
Danke Xie
  • 1,757
  • 17
  • 13
4

From the javadoc for Executors.newCachedThreadPool():

Threads that have not been used for sixty seconds are terminated and removed from the cache.

It is usually a good idea to call shutdown() on an ExecutorService if you know that no new tasks will be submitted to it. Then all tasks in the queue will complete, but the service will then shut down immediately.

(Alternately, if you don't care if all the tasks complete - for example, if they are handling background calculations that are irrelevant once your main UI is gone - then you can create a ThreadFactory that sets all the threads in that pool to be daemon.)

Gray
  • 115,027
  • 24
  • 293
  • 354
Russell Zahniser
  • 16,188
  • 39
  • 30
  • Thanks for your hint to call shutdown(), imho this is appropriate for my scenario – alapeno Nov 18 '13 at 21:08
  • After calling shutdown(), you also need to call awaitTerminate(...). Shutdown() does not wait for previously submitted tasks to finish. See also http://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish-using-executorservice – Danke Xie Feb 13 '15 at 10:15
0

For multi threading of ExecutorService Solution is threadPool.shutdown();

0

It is due to combination keepAliveTime=60L, timeunit=TimeUnit.SECONDS and corePoolSize=0*: when thread completes task, it does not terminate immediately, it may** wait during keepAliveTime for a new task.

 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

*if core poolSize != 0 see method allowCoreThreadTimeOut() of ThreadPoolExecutor

**waiting depends on combination of current quantity of running threads in pool, corePoolSize and maximumPoolSize