Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly shutdown executor services with Spring?

I have a command line application that uses a Spring-managed bean that's composed of a java ExecutorService created with:

ExecutorService service = Executors.newFixedThreadPool(4);

Now, I want my service to shutdown when my application shuts down, so I made my bean implement the DisposableBean interface and have a destroy method such as:

public void destroy(){
  service.shutdown();
}

Then I might be tempted to do something like register a shutdown hook on the Spring context. However I found out (the hard way, i.e., in a pre-production release) that this doesn't work: the shutdown hook doesn't get called before the ExecutorService.shutdown() method is called, causing a classic catch 22 problem (it does get called on interruption, i.e., if I hit Ctrl-C while the application is running). This escaped my unit tests because for some reason it seems to work fine from within JUnit, which is still puzzling me: what does JUnit do differently?

The solution I found so far is to explicitly call ApplicationContext.close() right before I exit my main function. I was wondering if there was a better solution to this and what are the best practices for having flexible thread pools managed by Spring. Also what if my bean is not directly managed by Spring but is created by a bean managed by Spring? Should I just cascade the calls to destroy()? Wouldn't this be very error prone?

I appreciate any comments, suggestions, further reading, RTFMs, magic recipes.

Thanks!

like image 230
Giovanni Botta Avatar asked Aug 29 '13 16:08

Giovanni Botta


People also ask

How do you shut down an executor service?

To properly shut down an ExecutorService, we have the shutdown() and shutdownNow() APIs. The shutdown() method doesn't cause immediate destruction of the ExecutorService. It will make the ExecutorService stop accepting new tasks and shut down after all running threads finish their current work: executorService.

How do I gracefully shutdown Spring services?

Use the static exit() method in the SpringApplication class for closing your spring boot application gracefully.

Should executor services be shut down?

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.

Which of the following is a preferred way of shutdown executors?

Best Practice. The correct way to shutdown the executor service, as suggested in Java docs, is as follows. It shuts down the executor service and waits for some time for submitted tasks to complete. If the running tasks do not complete in certain time, they are terminated forcefully.

What does the shutdown () method do to The ExecutorService?

The shutdown () method doesn't cause immediate destruction of the ExecutorService. It will make the ExecutorService stop accepting new tasks and shut down after all running threads finish their current work:

What is ExecutorService in Spring Boot?

This post would demo how to setup the ExecutorService in the springboot application. SpringBoot 1.5.12 Java 1.8 An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks.

How to control the termination of tasks submitted to executor?

ExecutorService interface provides 3 methods shutdown (), shutdownNow () and awaitTermination​ () for controlling the termination of tasks submitted to executor. Learn to use these methods under different requirements. 1. Difference between shutdown (), shutdownNow () and awaitTermination​ () APIs

How to shut down a Spring Boot application?

To shut down the Spring Boot application, we simply call a POST method like this: In this call, the port represents the actuator port. 3. Close Application Context We can also call the close () method directly using the application context. Let's start with an example of creating a context and closing it:


2 Answers

Are you aware that this:

ExecutorService service = Executors.newFixedThreadPool(4);

can be replaced with this:

<bean id="service" class="java.util.concurrent.Executors" 
      factory-method="newFixedThreadPool" destroy-method="shutdown">
    <constructor-arg value="4"/>
</bean>

The spring context then manages, more directly, the shutdown of your executor service--and it can be more easily reused.

like image 153
Keith Avatar answered Oct 06 '22 16:10

Keith


Per official Spring documentation, when using annotation-based configuration, for destroyMethod field of @Bean, Spring's default behavior is to automatically invoke public, no-arg methods named close or shutdown when the application context is being closed.

As a convenience to the user, the container will attempt to infer a destroy method against an object returned from the @Bean method. For example, given an @Bean method returning an Apache Commons DBCP BasicDataSource, the container will notice the close() method available on that object and automatically register it as the destroyMethod. This 'destroy method inference' is currently limited to detecting only public, no-arg methods named 'close' or 'shutdown'. The method may be declared at any level of the inheritance hierarchy and will be detected regardless of the return type of the @Bean method (i.e., detection occurs reflectively against the bean instance itself at creation time).

To re-iterate, this is the default behavior for annotation-driven configuration when a destroy method is not explicitly set. If this behavior is undesired explicitly setting destroy method to an empty string will disable this "feature":

To disable destroy method inference for a particular @Bean, specify an empty string as the value, e.g. @Bean(destroyMethod=""). Note that the DisposableBean and the Closeable/AutoCloseable interfaces will nevertheless get detected and the corresponding destroy/close method invoked.

On the other hand, when using XML configuration, this is not the default behavior... To achieve parity, destroy-method can be explicitly set to (inferred). Refer to the Destruction callbacks and Default initialization and destroy methods sections in the official docs for details.

like image 8
Andrey Avatar answered Oct 06 '22 15:10

Andrey